mass removal of underscores from _BB_DIR_foo and _BB_SUID_foo
[platform/upstream/busybox.git] / util-linux / blockdev.c
1 /*
2  * blockdev implementation for busybox
3  *
4  * Copyright (C) 2010 Sergey Naumov <sknaumov@gmail.com>
5  *
6  * Licensed under GPLv2, see file LICENSE in this source tree.
7  */
8
9 //applet:IF_BLOCKDEV(APPLET(blockdev, BB_DIR_SBIN, BB_SUID_DROP))
10
11 //kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o
12
13 //config:config BLOCKDEV
14 //config:       bool "blockdev"
15 //config:       default y
16 //config:       help
17 //config:         Performs some ioctls with block devices.
18
19 //usage:#define blockdev_trivial_usage
20 //usage:        "OPTION BLOCKDEV"
21 //usage:#define blockdev_full_usage "\n\n"
22 //usage:       "Options:"
23 //usage:     "\n        --setro         Set ro"
24 //usage:     "\n        --setrw         Set rw"
25 //usage:     "\n        --getro         Get ro"
26 //usage:     "\n        --getss         Get sector size"
27 //usage:     "\n        --getbsz        Get block size"
28 //usage:     "\n        --setbsz BYTES  Set block size"
29 //usage:     "\n        --getsize       Get device size in 512-byte sectors"
30 //usage:     "\n        --getsize64     Get device size in bytes"
31 //usage:     "\n        --flushbufs     Flush buffers"
32 //usage:     "\n        --rereadpt      Reread partition table"
33
34
35 #include "libbb.h"
36 #include <linux/fs.h>
37
38 enum {
39         ARG_NONE   = 0,
40         ARG_INT    = 1,
41         ARG_ULONG  = 2,
42         /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */
43         ARG_U64    = 3,
44         ARG_MASK   = 3,
45
46         FL_USRARG   = 4, /* argument is provided by user */
47         FL_NORESULT = 8,
48 };
49
50 struct bdc {
51         uint32_t   ioc;                       /* ioctl code */
52         const char name[sizeof("flushbufs")]; /* "--setfoo" wothout "--" */
53         uint8_t    flags;
54         int8_t     argval;                    /* default argument value */
55 };
56
57 static const struct bdc bdcommands[] = {
58         {
59                 .ioc = BLKROSET,
60                 .name = "setro",
61                 .flags = ARG_INT + FL_NORESULT,
62                 .argval = 1,
63         },{
64                 .ioc = BLKROSET,
65                 .name = "setrw",
66                 .flags = ARG_INT + FL_NORESULT,
67                 .argval = 0,
68         },{
69                 .ioc = BLKROGET,
70                 .name = "getro",
71                 .flags = ARG_INT,
72                 .argval = -1,
73         },{
74                 .ioc = BLKSSZGET,
75                 .name = "getss",
76                 .flags = ARG_INT,
77                 .argval = -1,
78         },{
79                 .ioc = BLKBSZGET,
80                 .name = "getbsz",
81                 .flags = ARG_INT,
82                 .argval = -1,
83         },{
84                 .ioc = BLKBSZSET,
85                 .name = "setbsz",
86                 .flags = ARG_INT + FL_NORESULT + FL_USRARG,
87                 .argval = 0,
88         },{
89                 .ioc = BLKGETSIZE,
90                 .name = "getsize",
91                 .flags = ARG_ULONG,
92                 .argval = -1,
93         },{
94                 .ioc = BLKGETSIZE64,
95                 .name = "getsize64",
96                 .flags = ARG_U64,
97                 .argval = -1,
98         },{
99                 .ioc = BLKFLSBUF,
100                 .name = "flushbufs",
101                 .flags = ARG_NONE + FL_NORESULT,
102                 .argval = 0,
103         },{
104                 .ioc = BLKRRPART,
105                 .name = "rereadpt",
106                 .flags = ARG_NONE + FL_NORESULT,
107                 .argval = 0,
108         }
109 };
110
111 static const struct bdc *find_cmd(const char *s)
112 {
113         const struct bdc *bdcmd = bdcommands;
114         if (s[0] == '-' && s[1] == '-') {
115                 s += 2;
116                 do {
117                         if (strcmp(s, bdcmd->name) == 0)
118                                 return bdcmd;
119                         bdcmd++;
120                 } while (bdcmd != bdcommands + ARRAY_SIZE(bdcommands));
121         }
122         bb_show_usage();
123 }
124
125 int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
126 int blockdev_main(int argc, char **argv)
127 {
128         const struct bdc *bdcmd;
129         int fd;
130         uint64_t u64;
131         union {
132                 int i;
133                 unsigned long lu;
134                 uint64_t u64;
135         } ioctl_val_on_stack;
136
137         if ((unsigned)(argc - 3) > 1) /* must have 2 or 3 args */
138                 bb_show_usage();
139
140         bdcmd = find_cmd(*++argv);
141
142         u64 = (int)bdcmd->argval;
143         if (bdcmd->flags & FL_USRARG)
144                 u64 = xatoi_positive(*++argv);
145
146         if (!*++argv || argv[1])
147                 bb_show_usage();
148         fd = xopen(*argv, O_RDONLY);
149
150         ioctl_val_on_stack.u64 = u64;
151 #if BB_BIG_ENDIAN
152         /* Store data properly wrt data size.
153          * (1) It's no-op for little-endian.
154          * (2) it's no-op for 0 and -1. Only --setro uses arg != 0 and != -1,
155          * and it is ARG_INT. --setbsz USER_VAL is also ARG_INT.
156          * Thus, we don't need to handle ARG_ULONG.
157          */
158         switch (bdcmd->flags & ARG_MASK) {
159         case ARG_INT:
160                 ioctl_val_on_stack.i = (int)u64;
161                 break;
162 # if 0 /* unused */
163         case ARG_ULONG:
164                 ioctl_val_on_stack.lu = (unsigned long)u64;
165                 break;
166 # endif
167         }
168 #endif
169
170         if (ioctl(fd, bdcmd->ioc, &ioctl_val_on_stack.u64) == -1)
171                 bb_simple_perror_msg_and_die(*argv);
172
173         /* Fetch it into register(s) */
174         u64 = ioctl_val_on_stack.u64;
175
176         /* Zero- or one-extend the value if needed, then print */
177         switch (bdcmd->flags & (ARG_MASK+FL_NORESULT)) {
178         case ARG_INT:
179                 /* Smaller code when we use long long
180                  * (gcc tail-merges printf call)
181                  */
182                 printf("%lld\n", (long long)(int)u64);
183                 break;
184         case ARG_ULONG:
185                 u64 = (unsigned long)u64;
186                 /* FALLTHROUGH */
187         case ARG_U64:
188                 printf("%llu\n", (unsigned long long)u64);
189                 break;
190         }
191
192         if (ENABLE_FEATURE_CLEAN_UP)
193                 close(fd);
194         return EXIT_SUCCESS;
195 }