blob: e25e529db2ddf273a380f82c32fe7c8944bf4c03 [file] [log] [blame]
Sergey Naumov289aff82010-09-06 13:35:58 +02001/*
2 * blockdev implementation for busybox
3 *
4 * Copyright (C) 2010 Sergey Naumov <sknaumov@gmail.com>
5 *
Denys Vlasenkof38b9122010-09-06 17:41:46 +02006 * Licensed under GPLv2, see file LICENSE in this source tree.
Sergey Naumov289aff82010-09-06 13:35:58 +02007 */
8
Denys Vlasenkob9f2d9f2011-01-18 13:58:01 +01009//applet:IF_BLOCKDEV(APPLET(blockdev, BB_DIR_SBIN, BB_SUID_DROP))
Sergey Naumov289aff82010-09-06 13:35:58 +020010
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
Denys Vlasenkob4e6b412010-09-06 14:15:46 +020020//usage: "OPTION BLOCKDEV"
Sergey Naumov289aff82010-09-06 13:35:58 +020021//usage:#define blockdev_full_usage "\n\n"
Denys Vlasenko66426762011-06-05 03:58:28 +020022//usage: " --setro Set ro"
Sergey Naumov289aff82010-09-06 13:35:58 +020023//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"
Dan Fandrichf303bdd2011-02-20 04:15:43 +010028//usage: "\n --getsz Get device size in 512-byte sectors"
29/*//usage: "\n --getsize Get device size in sectors (deprecated)"*/
Sergey Naumov289aff82010-09-06 13:35:58 +020030//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
38enum {
39 ARG_NONE = 0,
40 ARG_INT = 1,
41 ARG_ULONG = 2,
Denys Vlasenko571c5ab2010-09-06 17:37:52 +020042 /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */
43 ARG_U64 = 3,
Sergey Naumov289aff82010-09-06 13:35:58 +020044 ARG_MASK = 3,
45
46 FL_USRARG = 4, /* argument is provided by user */
47 FL_NORESULT = 8,
Dan Fandrichf303bdd2011-02-20 04:15:43 +010048 FL_SCALE512 = 16,
Sergey Naumov289aff82010-09-06 13:35:58 +020049};
50
51struct 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
58static 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 },{
Dan Fandrichf303bdd2011-02-20 04:15:43 +010090 .ioc = BLKGETSIZE64,
91 .name = "getsz",
92 .flags = ARG_U64 + FL_SCALE512,
93 .argval = -1,
94 },{
Sergey Naumov289aff82010-09-06 13:35:58 +020095 .ioc = BLKGETSIZE,
96 .name = "getsize",
97 .flags = ARG_ULONG,
98 .argval = -1,
99 },{
100 .ioc = BLKGETSIZE64,
101 .name = "getsize64",
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200102 .flags = ARG_U64,
Sergey Naumov289aff82010-09-06 13:35:58 +0200103 .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
117static const struct bdc *find_cmd(const char *s)
118{
Denys Vlasenko264bdad2010-09-06 15:34:15 +0200119 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 }
Sergey Naumov289aff82010-09-06 13:35:58 +0200128 bb_show_usage();
129}
130
131int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100132int blockdev_main(int argc UNUSED_PARAM, char **argv)
Sergey Naumov289aff82010-09-06 13:35:58 +0200133{
134 const struct bdc *bdcmd;
Sergey Naumov289aff82010-09-06 13:35:58 +0200135 int fd;
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200136 uint64_t u64;
137 union {
138 int i;
139 unsigned long lu;
140 uint64_t u64;
141 } ioctl_val_on_stack;
Sergey Naumov289aff82010-09-06 13:35:58 +0200142
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100143 argv++;
144 if (!argv[0] || !argv[1]) /* must have at least 2 args */
Sergey Naumov289aff82010-09-06 13:35:58 +0200145 bb_show_usage();
146
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100147 bdcmd = find_cmd(*argv);
Sergey Naumov289aff82010-09-06 13:35:58 +0200148
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200149 u64 = (int)bdcmd->argval;
Sergey Naumov289aff82010-09-06 13:35:58 +0200150 if (bdcmd->flags & FL_USRARG)
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200151 u64 = xatoi_positive(*++argv);
Sergey Naumov289aff82010-09-06 13:35:58 +0200152
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100153 argv++;
154 if (!argv[0] || argv[1])
Sergey Naumov289aff82010-09-06 13:35:58 +0200155 bb_show_usage();
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100156 fd = xopen(argv[0], O_RDONLY);
Sergey Naumov289aff82010-09-06 13:35:58 +0200157
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200158 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 */
Sergey Naumov289aff82010-09-06 13:35:58 +0200166 switch (bdcmd->flags & ARG_MASK) {
167 case ARG_INT:
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200168 ioctl_val_on_stack.i = (int)u64;
Sergey Naumov289aff82010-09-06 13:35:58 +0200169 break;
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200170# if 0 /* unused */
Sergey Naumov289aff82010-09-06 13:35:58 +0200171 case ARG_ULONG:
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200172 ioctl_val_on_stack.lu = (unsigned long)u64;
Sergey Naumov289aff82010-09-06 13:35:58 +0200173 break;
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200174# endif
Sergey Naumov289aff82010-09-06 13:35:58 +0200175 }
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200176#endif
Sergey Naumov289aff82010-09-06 13:35:58 +0200177
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200178 if (ioctl(fd, bdcmd->ioc, &ioctl_val_on_stack.u64) == -1)
Sergey Naumov289aff82010-09-06 13:35:58 +0200179 bb_simple_perror_msg_and_die(*argv);
180
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200181 /* Fetch it into register(s) */
182 u64 = ioctl_val_on_stack.u64;
183
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100184 if (bdcmd->flags & FL_SCALE512)
185 u64 >>= 9;
186
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200187 /* Zero- or one-extend the value if needed, then print */
Sergey Naumov289aff82010-09-06 13:35:58 +0200188 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 */
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200193 printf("%lld\n", (long long)(int)u64);
Sergey Naumov289aff82010-09-06 13:35:58 +0200194 break;
195 case ARG_ULONG:
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200196 u64 = (unsigned long)u64;
Sergey Naumov289aff82010-09-06 13:35:58 +0200197 /* FALLTHROUGH */
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200198 case ARG_U64:
199 printf("%llu\n", (unsigned long long)u64);
Sergey Naumov289aff82010-09-06 13:35:58 +0200200 break;
201 }
202
203 if (ENABLE_FEATURE_CLEAN_UP)
204 close(fd);
205 return EXIT_SUCCESS;
206}