2 * blockdev implementation for busybox
4 * Copyright (C) 2010 Sergey Naumov <sknaumov@gmail.com>
6 * Licensed under GPLv2, see file LICENSE in this source tree.
9 //applet:IF_BLOCKDEV(APPLET(blockdev, BB_DIR_SBIN, BB_SUID_DROP))
11 //kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o
13 //config:config BLOCKDEV
14 //config: bool "blockdev"
17 //config: Performs some ioctls with block devices.
19 //usage:#define blockdev_trivial_usage
20 //usage: "OPTION BLOCKDEV"
21 //usage:#define blockdev_full_usage "\n\n"
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 --getsz Get device size in 512-byte sectors"
30 /*//usage: "\n --getsize Get device size in sectors (deprecated)"*/
31 //usage: "\n --getsize64 Get device size in bytes"
32 //usage: "\n --flushbufs Flush buffers"
33 //usage: "\n --rereadpt Reread partition table"
43 /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */
47 FL_USRARG = 4, /* argument is provided by user */
53 uint32_t ioc; /* ioctl code */
54 const char name[sizeof("flushbufs")]; /* "--setfoo" wothout "--" */
56 int8_t argval; /* default argument value */
59 static const struct bdc bdcommands[] = {
63 .flags = ARG_INT + FL_NORESULT,
68 .flags = ARG_INT + FL_NORESULT,
88 .flags = ARG_INT + FL_NORESULT + FL_USRARG,
93 .flags = ARG_U64 + FL_SCALE512,
108 .flags = ARG_NONE + FL_NORESULT,
113 .flags = ARG_NONE + FL_NORESULT,
118 static const struct bdc *find_cmd(const char *s)
120 const struct bdc *bdcmd = bdcommands;
121 if (s[0] == '-' && s[1] == '-') {
124 if (strcmp(s, bdcmd->name) == 0)
127 } while (bdcmd != bdcommands + ARRAY_SIZE(bdcommands));
132 int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
133 int blockdev_main(int argc UNUSED_PARAM, char **argv)
135 const struct bdc *bdcmd;
142 } ioctl_val_on_stack;
145 if (!argv[0] || !argv[1]) /* must have at least 2 args */
148 bdcmd = find_cmd(*argv);
150 u64 = (int)bdcmd->argval;
151 if (bdcmd->flags & FL_USRARG)
152 u64 = xatoi_positive(*++argv);
155 if (!argv[0] || argv[1])
157 fd = xopen(argv[0], O_RDONLY);
159 ioctl_val_on_stack.u64 = u64;
161 /* Store data properly wrt data size.
162 * (1) It's no-op for little-endian.
163 * (2) it's no-op for 0 and -1. Only --setro uses arg != 0 and != -1,
164 * and it is ARG_INT. --setbsz USER_VAL is also ARG_INT.
165 * Thus, we don't need to handle ARG_ULONG.
167 switch (bdcmd->flags & ARG_MASK) {
169 ioctl_val_on_stack.i = (int)u64;
173 ioctl_val_on_stack.lu = (unsigned long)u64;
179 if (ioctl(fd, bdcmd->ioc, &ioctl_val_on_stack.u64) == -1)
180 bb_simple_perror_msg_and_die(*argv);
182 /* Fetch it into register(s) */
183 u64 = ioctl_val_on_stack.u64;
185 if (bdcmd->flags & FL_SCALE512)
188 /* Zero- or one-extend the value if needed, then print */
189 switch (bdcmd->flags & (ARG_MASK+FL_NORESULT)) {
191 /* Smaller code when we use long long
192 * (gcc tail-merges printf call)
194 printf("%lld\n", (long long)(int)u64);
197 u64 = (unsigned long)u64;
200 printf("%llu\n", (unsigned long long)u64);
204 if (ENABLE_FEATURE_CLEAN_UP)