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.
8 //config:config BLOCKDEV
9 //config: bool "blockdev (2.3 kb)"
12 //config: Performs some ioctls with block devices.
14 //applet:IF_BLOCKDEV(APPLET_NOEXEC(blockdev, blockdev, BB_DIR_SBIN, BB_SUID_DROP, blockdev))
16 //kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o
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 // util-linux 2.31 also has:
33 // --getdiscardzeroes BLKDISCARDZEROES Get discard zeroes support status
34 // --getpbsz BLKPBSZGET Get physical block (sector) size
35 // --getiomin BLKIOMIN Get minimum I/O size
36 // --getioopt BLKIOOPT Get optimal I/O size
37 // --getalignoff BLKALIGNOFF Get alignment offset in bytes
38 // --getmaxsect BLKSECTGET Get max sectors per request
39 // --setra SECTORS BLKRASET Set readahead
40 // --getra BLKRAGET Get readahead
41 // --setfra SECTORS BLKFRASET Set filesystem readahead
42 // --getfra BLKFRAGET Get filesystem readahead
47 /* Takes less space is separate arrays than one array of struct */
48 static const char bdcmd_names[] ALIGN1 =
63 static const uint32_t bdcmd_ioctl[] = {
72 BLKGETSIZE64, //getsize64
73 BLKFLSBUF, //flushbufs
80 /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */
84 FL_USRARG = 4, /* argument is provided by user */
88 static const uint8_t bdcmd_flags[] ALIGN1 = {
89 ARG_INT + FL_NORESULT, //setro
90 ARG_INT + FL_NORESULT, //setrw
94 ARG_INT + FL_NORESULT + FL_USRARG, //setbsz
95 ARG_U64 + FL_SCALE512, //getsz
98 ARG_NONE + FL_NORESULT, //flushbufs
99 ARG_NONE + FL_NORESULT, //rereadpt
102 static unsigned find_cmd(const char *s)
104 if (s[0] == '-' && s[1] == '-') {
105 int n = index_in_strings(bdcmd_names, s + 2);
112 int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
113 int blockdev_main(int argc UNUSED_PARAM, char **argv)
123 } ioctl_val_on_stack;
126 if (!argv[0] || !argv[1]) /* must have at least 2 args */
129 bdcmd = find_cmd(*argv);
130 /* setrw translates to BLKROSET(0), most other ioctls don't care... */
131 /* ...setro will do BLKROSET(1) */
132 u64 = (bdcmd == CMD_SETRO);
133 if (bdcmd == CMD_SETBSZ) {
134 /* ...setbsz is BLKBSZSET(bytes) */
135 u64 = xatoi_positive(*++argv);
139 if (!argv[0] || argv[1])
141 fd = xopen(argv[0], O_RDONLY);
143 ioctl_val_on_stack.u64 = u64;
144 flags = bdcmd_flags[bdcmd];
146 /* Store data properly wrt data size.
147 * (1) It's no-op for little-endian.
148 * (2) it's no-op for 0 and -1. Only --setro uses arg != 0 and != -1,
149 * and it is ARG_INT. --setbsz USER_VAL is also ARG_INT.
150 * Thus, we don't need to handle ARG_ULONG.
152 switch (flags & ARG_MASK) {
154 ioctl_val_on_stack.i = (int)u64;
158 ioctl_val_on_stack.lu = (unsigned long)u64;
164 if (ioctl(fd, bdcmd_ioctl[bdcmd], &ioctl_val_on_stack.u64) == -1)
165 bb_simple_perror_msg_and_die(*argv);
167 /* Fetch it into register(s) */
168 u64 = ioctl_val_on_stack.u64;
170 if (flags & FL_SCALE512)
173 /* Zero- or one-extend the value if needed, then print */
174 switch (flags & (ARG_MASK+FL_NORESULT)) {
176 /* Smaller code when we use long long
177 * (gcc tail-merges printf call)
179 printf("%lld\n", (long long)(int)u64);
182 u64 = (unsigned long)u64;
185 printf("%llu\n", (unsigned long long)u64);
189 if (ENABLE_FEATURE_CLEAN_UP)