bc: convert to "G trick" - this returns bc to zero bss increase
[oweals/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 //config:config BLOCKDEV
9 //config:       bool "blockdev (2.4 kb)"
10 //config:       default y
11 //config:       help
12 //config:       Performs some ioctls with block devices.
13
14 //applet:IF_BLOCKDEV(APPLET_NOEXEC(blockdev, blockdev, BB_DIR_SBIN, BB_SUID_DROP, blockdev))
15
16 //kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o
17
18 //usage:#define blockdev_trivial_usage
19 //usage:        "OPTION BLOCKDEV"
20 //usage:#define blockdev_full_usage "\n\n"
21 //usage:       "        --setro         Set ro"
22 //usage:     "\n        --setrw         Set rw"
23 //usage:     "\n        --getro         Get ro"
24 //usage:     "\n        --getss         Get sector size"
25 //usage:     "\n        --getbsz        Get block size"
26 //usage:     "\n        --setbsz BYTES  Set block size"
27 //usage:     "\n        --getsz         Get device size in 512-byte sectors"
28 /*//usage:     "\n      --getsize       Get device size in sectors (deprecated)"*/
29 //usage:     "\n        --getsize64     Get device size in bytes"
30 //usage:     "\n        --flushbufs     Flush buffers"
31 //usage:     "\n        --rereadpt      Reread partition table"
32
33
34 #include "libbb.h"
35 #include <linux/fs.h>
36
37 enum {
38         ARG_NONE   = 0,
39         ARG_INT    = 1,
40         ARG_ULONG  = 2,
41         /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */
42         ARG_U64    = 3,
43         ARG_MASK   = 3,
44
45         FL_USRARG   = 4, /* argument is provided by user */
46         FL_NORESULT = 8,
47         FL_SCALE512 = 16,
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 = BLKGETSIZE64,
90                 .name = "getsz",
91                 .flags = ARG_U64 + FL_SCALE512,
92                 .argval = -1,
93         },{
94                 .ioc = BLKGETSIZE,
95                 .name = "getsize",
96                 .flags = ARG_ULONG,
97                 .argval = -1,
98         },{
99                 .ioc = BLKGETSIZE64,
100                 .name = "getsize64",
101                 .flags = ARG_U64,
102                 .argval = -1,
103         },{
104                 .ioc = BLKFLSBUF,
105                 .name = "flushbufs",
106                 .flags = ARG_NONE + FL_NORESULT,
107                 .argval = 0,
108         },{
109                 .ioc = BLKRRPART,
110                 .name = "rereadpt",
111                 .flags = ARG_NONE + FL_NORESULT,
112                 .argval = 0,
113         }
114 };
115
116 static const struct bdc *find_cmd(const char *s)
117 {
118         const struct bdc *bdcmd = bdcommands;
119         if (s[0] == '-' && s[1] == '-') {
120                 s += 2;
121                 do {
122                         if (strcmp(s, bdcmd->name) == 0)
123                                 return bdcmd;
124                         bdcmd++;
125                 } while (bdcmd != bdcommands + ARRAY_SIZE(bdcommands));
126         }
127         bb_show_usage();
128 }
129
130 int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
131 int blockdev_main(int argc UNUSED_PARAM, char **argv)
132 {
133         const struct bdc *bdcmd;
134         int fd;
135         uint64_t u64;
136         union {
137                 int i;
138                 unsigned long lu;
139                 uint64_t u64;
140         } ioctl_val_on_stack;
141
142         argv++;
143         if (!argv[0] || !argv[1]) /* must have at least 2 args */
144                 bb_show_usage();
145
146         bdcmd = find_cmd(*argv);
147
148         u64 = (int)bdcmd->argval;
149         if (bdcmd->flags & FL_USRARG)
150                 u64 = xatoi_positive(*++argv);
151
152         argv++;
153         if (!argv[0] || argv[1])
154                 bb_show_usage();
155         fd = xopen(argv[0], O_RDONLY);
156
157         ioctl_val_on_stack.u64 = u64;
158 #if BB_BIG_ENDIAN
159         /* Store data properly wrt data size.
160          * (1) It's no-op for little-endian.
161          * (2) it's no-op for 0 and -1. Only --setro uses arg != 0 and != -1,
162          * and it is ARG_INT. --setbsz USER_VAL is also ARG_INT.
163          * Thus, we don't need to handle ARG_ULONG.
164          */
165         switch (bdcmd->flags & ARG_MASK) {
166         case ARG_INT:
167                 ioctl_val_on_stack.i = (int)u64;
168                 break;
169 # if 0 /* unused */
170         case ARG_ULONG:
171                 ioctl_val_on_stack.lu = (unsigned long)u64;
172                 break;
173 # endif
174         }
175 #endif
176
177         if (ioctl(fd, bdcmd->ioc, &ioctl_val_on_stack.u64) == -1)
178                 bb_simple_perror_msg_and_die(*argv);
179
180         /* Fetch it into register(s) */
181         u64 = ioctl_val_on_stack.u64;
182
183         if (bdcmd->flags & FL_SCALE512)
184                 u64 >>= 9;
185
186         /* Zero- or one-extend the value if needed, then print */
187         switch (bdcmd->flags & (ARG_MASK+FL_NORESULT)) {
188         case ARG_INT:
189                 /* Smaller code when we use long long
190                  * (gcc tail-merges printf call)
191                  */
192                 printf("%lld\n", (long long)(int)u64);
193                 break;
194         case ARG_ULONG:
195                 u64 = (unsigned long)u64;
196                 /* FALLTHROUGH */
197         case ARG_U64:
198                 printf("%llu\n", (unsigned long long)u64);
199                 break;
200         }
201
202         if (ENABLE_FEATURE_CLEAN_UP)
203                 close(fd);
204         return EXIT_SUCCESS;
205 }