blob: 4aed02982bab0338fae45ad2fbd7e98cf8e6cc75 [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"
22//usage: "Options:"
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"
Dan Fandrichf303bdd2011-02-20 04:15:43 +010029//usage: "\n --getsz Get device size in 512-byte sectors"
30/*//usage: "\n --getsize Get device size in sectors (deprecated)"*/
Sergey Naumov289aff82010-09-06 13:35:58 +020031//usage: "\n --getsize64 Get device size in bytes"
32//usage: "\n --flushbufs Flush buffers"
33//usage: "\n --rereadpt Reread partition table"
34
35
36#include "libbb.h"
37#include <linux/fs.h>
38
39enum {
40 ARG_NONE = 0,
41 ARG_INT = 1,
42 ARG_ULONG = 2,
Denys Vlasenko571c5ab2010-09-06 17:37:52 +020043 /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */
44 ARG_U64 = 3,
Sergey Naumov289aff82010-09-06 13:35:58 +020045 ARG_MASK = 3,
46
47 FL_USRARG = 4, /* argument is provided by user */
48 FL_NORESULT = 8,
Dan Fandrichf303bdd2011-02-20 04:15:43 +010049 FL_SCALE512 = 16,
Sergey Naumov289aff82010-09-06 13:35:58 +020050};
51
52struct bdc {
53 uint32_t ioc; /* ioctl code */
54 const char name[sizeof("flushbufs")]; /* "--setfoo" wothout "--" */
55 uint8_t flags;
56 int8_t argval; /* default argument value */
57};
58
59static const struct bdc bdcommands[] = {
60 {
61 .ioc = BLKROSET,
62 .name = "setro",
63 .flags = ARG_INT + FL_NORESULT,
64 .argval = 1,
65 },{
66 .ioc = BLKROSET,
67 .name = "setrw",
68 .flags = ARG_INT + FL_NORESULT,
69 .argval = 0,
70 },{
71 .ioc = BLKROGET,
72 .name = "getro",
73 .flags = ARG_INT,
74 .argval = -1,
75 },{
76 .ioc = BLKSSZGET,
77 .name = "getss",
78 .flags = ARG_INT,
79 .argval = -1,
80 },{
81 .ioc = BLKBSZGET,
82 .name = "getbsz",
83 .flags = ARG_INT,
84 .argval = -1,
85 },{
86 .ioc = BLKBSZSET,
87 .name = "setbsz",
88 .flags = ARG_INT + FL_NORESULT + FL_USRARG,
89 .argval = 0,
90 },{
Dan Fandrichf303bdd2011-02-20 04:15:43 +010091 .ioc = BLKGETSIZE64,
92 .name = "getsz",
93 .flags = ARG_U64 + FL_SCALE512,
94 .argval = -1,
95 },{
Sergey Naumov289aff82010-09-06 13:35:58 +020096 .ioc = BLKGETSIZE,
97 .name = "getsize",
98 .flags = ARG_ULONG,
99 .argval = -1,
100 },{
101 .ioc = BLKGETSIZE64,
102 .name = "getsize64",
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200103 .flags = ARG_U64,
Sergey Naumov289aff82010-09-06 13:35:58 +0200104 .argval = -1,
105 },{
106 .ioc = BLKFLSBUF,
107 .name = "flushbufs",
108 .flags = ARG_NONE + FL_NORESULT,
109 .argval = 0,
110 },{
111 .ioc = BLKRRPART,
112 .name = "rereadpt",
113 .flags = ARG_NONE + FL_NORESULT,
114 .argval = 0,
115 }
116};
117
118static const struct bdc *find_cmd(const char *s)
119{
Denys Vlasenko264bdad2010-09-06 15:34:15 +0200120 const struct bdc *bdcmd = bdcommands;
121 if (s[0] == '-' && s[1] == '-') {
122 s += 2;
123 do {
124 if (strcmp(s, bdcmd->name) == 0)
125 return bdcmd;
126 bdcmd++;
127 } while (bdcmd != bdcommands + ARRAY_SIZE(bdcommands));
128 }
Sergey Naumov289aff82010-09-06 13:35:58 +0200129 bb_show_usage();
130}
131
132int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100133int blockdev_main(int argc UNUSED_PARAM, char **argv)
Sergey Naumov289aff82010-09-06 13:35:58 +0200134{
135 const struct bdc *bdcmd;
Sergey Naumov289aff82010-09-06 13:35:58 +0200136 int fd;
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200137 uint64_t u64;
138 union {
139 int i;
140 unsigned long lu;
141 uint64_t u64;
142 } ioctl_val_on_stack;
Sergey Naumov289aff82010-09-06 13:35:58 +0200143
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100144 argv++;
145 if (!argv[0] || !argv[1]) /* must have at least 2 args */
Sergey Naumov289aff82010-09-06 13:35:58 +0200146 bb_show_usage();
147
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100148 bdcmd = find_cmd(*argv);
Sergey Naumov289aff82010-09-06 13:35:58 +0200149
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200150 u64 = (int)bdcmd->argval;
Sergey Naumov289aff82010-09-06 13:35:58 +0200151 if (bdcmd->flags & FL_USRARG)
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200152 u64 = xatoi_positive(*++argv);
Sergey Naumov289aff82010-09-06 13:35:58 +0200153
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100154 argv++;
155 if (!argv[0] || argv[1])
Sergey Naumov289aff82010-09-06 13:35:58 +0200156 bb_show_usage();
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100157 fd = xopen(argv[0], O_RDONLY);
Sergey Naumov289aff82010-09-06 13:35:58 +0200158
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200159 ioctl_val_on_stack.u64 = u64;
160#if BB_BIG_ENDIAN
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.
166 */
Sergey Naumov289aff82010-09-06 13:35:58 +0200167 switch (bdcmd->flags & ARG_MASK) {
168 case ARG_INT:
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200169 ioctl_val_on_stack.i = (int)u64;
Sergey Naumov289aff82010-09-06 13:35:58 +0200170 break;
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200171# if 0 /* unused */
Sergey Naumov289aff82010-09-06 13:35:58 +0200172 case ARG_ULONG:
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200173 ioctl_val_on_stack.lu = (unsigned long)u64;
Sergey Naumov289aff82010-09-06 13:35:58 +0200174 break;
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200175# endif
Sergey Naumov289aff82010-09-06 13:35:58 +0200176 }
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200177#endif
Sergey Naumov289aff82010-09-06 13:35:58 +0200178
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200179 if (ioctl(fd, bdcmd->ioc, &ioctl_val_on_stack.u64) == -1)
Sergey Naumov289aff82010-09-06 13:35:58 +0200180 bb_simple_perror_msg_and_die(*argv);
181
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200182 /* Fetch it into register(s) */
183 u64 = ioctl_val_on_stack.u64;
184
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100185 if (bdcmd->flags & FL_SCALE512)
186 u64 >>= 9;
187
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200188 /* Zero- or one-extend the value if needed, then print */
Sergey Naumov289aff82010-09-06 13:35:58 +0200189 switch (bdcmd->flags & (ARG_MASK+FL_NORESULT)) {
190 case ARG_INT:
191 /* Smaller code when we use long long
192 * (gcc tail-merges printf call)
193 */
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200194 printf("%lld\n", (long long)(int)u64);
Sergey Naumov289aff82010-09-06 13:35:58 +0200195 break;
196 case ARG_ULONG:
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200197 u64 = (unsigned long)u64;
Sergey Naumov289aff82010-09-06 13:35:58 +0200198 /* FALLTHROUGH */
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200199 case ARG_U64:
200 printf("%llu\n", (unsigned long long)u64);
Sergey Naumov289aff82010-09-06 13:35:58 +0200201 break;
202 }
203
204 if (ENABLE_FEATURE_CLEAN_UP)
205 close(fd);
206 return EXIT_SUCCESS;
207}