blob: c2fcaee88ac6ce585dfdb6b4b3b7e1e6c71cd159 [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"
29//usage: "\n --getsize Get device size in 512-byte sectors"
30//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,
48};
49
50struct 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
57static 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 = BLKGETSIZE,
90 .name = "getsize",
91 .flags = ARG_ULONG,
92 .argval = -1,
93 },{
94 .ioc = BLKGETSIZE64,
95 .name = "getsize64",
Denys Vlasenko571c5ab2010-09-06 17:37:52 +020096 .flags = ARG_U64,
Sergey Naumov289aff82010-09-06 13:35:58 +020097 .argval = -1,
98 },{
99 .ioc = BLKFLSBUF,
100 .name = "flushbufs",
101 .flags = ARG_NONE + FL_NORESULT,
102 .argval = 0,
103 },{
104 .ioc = BLKRRPART,
105 .name = "rereadpt",
106 .flags = ARG_NONE + FL_NORESULT,
107 .argval = 0,
108 }
109};
110
111static const struct bdc *find_cmd(const char *s)
112{
Denys Vlasenko264bdad2010-09-06 15:34:15 +0200113 const struct bdc *bdcmd = bdcommands;
114 if (s[0] == '-' && s[1] == '-') {
115 s += 2;
116 do {
117 if (strcmp(s, bdcmd->name) == 0)
118 return bdcmd;
119 bdcmd++;
120 } while (bdcmd != bdcommands + ARRAY_SIZE(bdcommands));
121 }
Sergey Naumov289aff82010-09-06 13:35:58 +0200122 bb_show_usage();
123}
124
125int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
126int blockdev_main(int argc, char **argv)
127{
128 const struct bdc *bdcmd;
Sergey Naumov289aff82010-09-06 13:35:58 +0200129 int fd;
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200130 uint64_t u64;
131 union {
132 int i;
133 unsigned long lu;
134 uint64_t u64;
135 } ioctl_val_on_stack;
Sergey Naumov289aff82010-09-06 13:35:58 +0200136
137 if ((unsigned)(argc - 3) > 1) /* must have 2 or 3 args */
138 bb_show_usage();
139
140 bdcmd = find_cmd(*++argv);
141
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200142 u64 = (int)bdcmd->argval;
Sergey Naumov289aff82010-09-06 13:35:58 +0200143 if (bdcmd->flags & FL_USRARG)
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200144 u64 = xatoi_positive(*++argv);
Sergey Naumov289aff82010-09-06 13:35:58 +0200145
Denys Vlasenkoa35dfe62010-09-06 16:31:18 +0200146 if (!*++argv || argv[1])
Sergey Naumov289aff82010-09-06 13:35:58 +0200147 bb_show_usage();
148 fd = xopen(*argv, O_RDONLY);
149
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200150 ioctl_val_on_stack.u64 = u64;
151#if BB_BIG_ENDIAN
152 /* Store data properly wrt data size.
153 * (1) It's no-op for little-endian.
154 * (2) it's no-op for 0 and -1. Only --setro uses arg != 0 and != -1,
155 * and it is ARG_INT. --setbsz USER_VAL is also ARG_INT.
156 * Thus, we don't need to handle ARG_ULONG.
157 */
Sergey Naumov289aff82010-09-06 13:35:58 +0200158 switch (bdcmd->flags & ARG_MASK) {
159 case ARG_INT:
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200160 ioctl_val_on_stack.i = (int)u64;
Sergey Naumov289aff82010-09-06 13:35:58 +0200161 break;
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200162# if 0 /* unused */
Sergey Naumov289aff82010-09-06 13:35:58 +0200163 case ARG_ULONG:
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200164 ioctl_val_on_stack.lu = (unsigned long)u64;
Sergey Naumov289aff82010-09-06 13:35:58 +0200165 break;
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200166# endif
Sergey Naumov289aff82010-09-06 13:35:58 +0200167 }
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200168#endif
Sergey Naumov289aff82010-09-06 13:35:58 +0200169
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200170 if (ioctl(fd, bdcmd->ioc, &ioctl_val_on_stack.u64) == -1)
Sergey Naumov289aff82010-09-06 13:35:58 +0200171 bb_simple_perror_msg_and_die(*argv);
172
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200173 /* Fetch it into register(s) */
174 u64 = ioctl_val_on_stack.u64;
175
176 /* Zero- or one-extend the value if needed, then print */
Sergey Naumov289aff82010-09-06 13:35:58 +0200177 switch (bdcmd->flags & (ARG_MASK+FL_NORESULT)) {
178 case ARG_INT:
179 /* Smaller code when we use long long
180 * (gcc tail-merges printf call)
181 */
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200182 printf("%lld\n", (long long)(int)u64);
Sergey Naumov289aff82010-09-06 13:35:58 +0200183 break;
184 case ARG_ULONG:
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200185 u64 = (unsigned long)u64;
Sergey Naumov289aff82010-09-06 13:35:58 +0200186 /* FALLTHROUGH */
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200187 case ARG_U64:
188 printf("%llu\n", (unsigned long long)u64);
Sergey Naumov289aff82010-09-06 13:35:58 +0200189 break;
190 }
191
192 if (ENABLE_FEATURE_CLEAN_UP)
193 close(fd);
194 return EXIT_SUCCESS;
195}