Bump to version 1.22.1
[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:       "        --setro         Set ro"
23 //usage:     "\n        --setrw         Set rw"
24 //usage:     "\n        --getro         Get ro"
25 //usage:     "\n        --getss         Get sector size"
26 //usage:     "\n        --getbsz        Get block size"
27 //usage:     "\n        --setbsz BYTES  Set block size"
28 //usage:     "\n        --getsz         Get device size in 512-byte sectors"
29 /*//usage:     "\n      --getsize       Get device size in sectors (deprecated)"*/
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         FL_SCALE512 = 16,
49 };
50
51 struct bdc {
52         uint32_t   ioc;                       /* ioctl code */
53         const char name[sizeof("flushbufs")]; /* "--setfoo" wothout "--" */
54         uint8_t    flags;
55         int8_t     argval;                    /* default argument value */
56 };
57
58 static const struct bdc bdcommands[] = {
59         {
60                 .ioc = BLKROSET,
61                 .name = "setro",
62                 .flags = ARG_INT + FL_NORESULT,
63                 .argval = 1,
64         },{
65                 .ioc = BLKROSET,
66                 .name = "setrw",
67                 .flags = ARG_INT + FL_NORESULT,
68                 .argval = 0,
69         },{
70                 .ioc = BLKROGET,
71                 .name = "getro",
72                 .flags = ARG_INT,
73                 .argval = -1,
74         },{
75                 .ioc = BLKSSZGET,
76                 .name = "getss",
77                 .flags = ARG_INT,
78                 .argval = -1,
79         },{
80                 .ioc = BLKBSZGET,
81                 .name = "getbsz",
82                 .flags = ARG_INT,
83                 .argval = -1,
84         },{
85                 .ioc = BLKBSZSET,
86                 .name = "setbsz",
87                 .flags = ARG_INT + FL_NORESULT + FL_USRARG,
88                 .argval = 0,
89         },{
90                 .ioc = BLKGETSIZE64,
91                 .name = "getsz",
92                 .flags = ARG_U64 + FL_SCALE512,
93                 .argval = -1,
94         },{
95                 .ioc = BLKGETSIZE,
96                 .name = "getsize",
97                 .flags = ARG_ULONG,
98                 .argval = -1,
99         },{
100                 .ioc = BLKGETSIZE64,
101                 .name = "getsize64",
102                 .flags = ARG_U64,
103                 .argval = -1,
104         },{
105                 .ioc = BLKFLSBUF,
106                 .name = "flushbufs",
107                 .flags = ARG_NONE + FL_NORESULT,
108                 .argval = 0,
109         },{
110                 .ioc = BLKRRPART,
111                 .name = "rereadpt",
112                 .flags = ARG_NONE + FL_NORESULT,
113                 .argval = 0,
114         }
115 };
116
117 static const struct bdc *find_cmd(const char *s)
118 {
119         const struct bdc *bdcmd = bdcommands;
120         if (s[0] == '-' && s[1] == '-') {
121                 s += 2;
122                 do {
123                         if (strcmp(s, bdcmd->name) == 0)
124                                 return bdcmd;
125                         bdcmd++;
126                 } while (bdcmd != bdcommands + ARRAY_SIZE(bdcommands));
127         }
128         bb_show_usage();
129 }
130
131 int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
132 int blockdev_main(int argc UNUSED_PARAM, char **argv)
133 {
134         const struct bdc *bdcmd;
135         int fd;
136         uint64_t u64;
137         union {
138                 int i;
139                 unsigned long lu;
140                 uint64_t u64;
141         } ioctl_val_on_stack;
142
143         argv++;
144         if (!argv[0] || !argv[1]) /* must have at least 2 args */
145                 bb_show_usage();
146
147         bdcmd = find_cmd(*argv);
148
149         u64 = (int)bdcmd->argval;
150         if (bdcmd->flags & FL_USRARG)
151                 u64 = xatoi_positive(*++argv);
152
153         argv++;
154         if (!argv[0] || argv[1])
155                 bb_show_usage();
156         fd = xopen(argv[0], O_RDONLY);
157
158         ioctl_val_on_stack.u64 = u64;
159 #if BB_BIG_ENDIAN
160         /* Store data properly wrt data size.
161          * (1) It's no-op for little-endian.
162          * (2) it's no-op for 0 and -1. Only --setro uses arg != 0 and != -1,
163          * and it is ARG_INT. --setbsz USER_VAL is also ARG_INT.
164          * Thus, we don't need to handle ARG_ULONG.
165          */
166         switch (bdcmd->flags & ARG_MASK) {
167         case ARG_INT:
168                 ioctl_val_on_stack.i = (int)u64;
169                 break;
170 # if 0 /* unused */
171         case ARG_ULONG:
172                 ioctl_val_on_stack.lu = (unsigned long)u64;
173                 break;
174 # endif
175         }
176 #endif
177
178         if (ioctl(fd, bdcmd->ioc, &ioctl_val_on_stack.u64) == -1)
179                 bb_simple_perror_msg_and_die(*argv);
180
181         /* Fetch it into register(s) */
182         u64 = ioctl_val_on_stack.u64;
183
184         if (bdcmd->flags & FL_SCALE512)
185                 u64 >>= 9;
186
187         /* Zero- or one-extend the value if needed, then print */
188         switch (bdcmd->flags & (ARG_MASK+FL_NORESULT)) {
189         case ARG_INT:
190                 /* Smaller code when we use long long
191                  * (gcc tail-merges printf call)
192                  */
193                 printf("%lld\n", (long long)(int)u64);
194                 break;
195         case ARG_ULONG:
196                 u64 = (unsigned long)u64;
197                 /* FALLTHROUGH */
198         case ARG_U64:
199                 printf("%llu\n", (unsigned long long)u64);
200                 break;
201         }
202
203         if (ENABLE_FEATURE_CLEAN_UP)
204                 close(fd);
205         return EXIT_SUCCESS;
206 }