]>
Commit | Line | Data |
---|---|---|
eb63b9b8 KZ |
1 | /* |
2 | * blockdev.c --- Do various simple block device ioctls from the command line | |
3 | * aeb, 991028 | |
4 | */ | |
5 | ||
6 | #include <stdio.h> | |
7 | #include <fcntl.h> | |
eb63b9b8 KZ |
8 | #include <stdlib.h> |
9 | #include <string.h> | |
10 | #include <unistd.h> | |
11 | #include <sys/ioctl.h> | |
3281d426 | 12 | #include <errno.h> |
eb63b9b8 | 13 | |
515422fd | 14 | #include "c.h" |
eb63b9b8 | 15 | #include "nls.h" |
bc8b6383 | 16 | #include "blkdev.h" |
14c76d8b | 17 | #include "pathnames.h" |
45ca68ec | 18 | #include "closestream.h" |
569d1dac | 19 | #include "sysfs.h" |
612721db | 20 | |
eb63b9b8 | 21 | struct bdc { |
c3f62be7 KZ |
22 | long ioc; /* ioctl code */ |
23 | const char *iocname; /* ioctl name (e.g. BLKROSET) */ | |
24 | long argval; /* default argument */ | |
25 | ||
26 | const char *name; /* --setfoo */ | |
27 | const char *argname; /* argument name or NULL */ | |
28 | ||
29 | const char *help; | |
30 | ||
31 | int argtype; | |
32 | int flags; | |
33 | }; | |
34 | ||
35 | /* command flags */ | |
36 | enum { | |
37 | FL_NOPTR = (1 << 1), /* does not assume pointer (ARG_INT only)*/ | |
38 | FL_NORESULT = (1 << 2) /* does not return any data */ | |
39 | }; | |
40 | ||
41 | /* ioctl argument types */ | |
42 | enum { | |
43 | ARG_NONE, | |
726fa24e | 44 | ARG_USHRT, |
c3f62be7 | 45 | ARG_INT, |
726fa24e | 46 | ARG_UINT, |
c3f62be7 KZ |
47 | ARG_LONG, |
48 | ARG_ULONG, | |
49 | ARG_LLONG, | |
50 | ARG_ULLONG | |
51 | }; | |
52 | ||
53 | #define IOCTL_ENTRY( io ) .ioc = io, .iocname = # io | |
54 | ||
00239f33 | 55 | static const struct bdc bdcms[] = |
c3f62be7 KZ |
56 | { |
57 | { | |
58 | IOCTL_ENTRY(BLKROSET), | |
59 | .name = "--setro", | |
60 | .argtype = ARG_INT, | |
61 | .argval = 1, | |
62 | .flags = FL_NORESULT, | |
63 | .help = N_("set read-only") | |
64 | },{ | |
65 | IOCTL_ENTRY(BLKROSET), | |
66 | .name = "--setrw", | |
67 | .argtype = ARG_INT, | |
68 | .argval = 0, | |
69 | .flags = FL_NORESULT, | |
70 | .help = N_("set read-write") | |
71 | },{ | |
72 | IOCTL_ENTRY(BLKROGET), | |
73 | .name = "--getro", | |
74 | .argtype = ARG_INT, | |
75 | .argval = -1, | |
76 | .help = N_("get read-only") | |
1519ab5f KZ |
77 | },{ |
78 | IOCTL_ENTRY(BLKDISCARDZEROES), | |
79 | .name = "--getdiscardzeroes", | |
80 | .argtype = ARG_UINT, | |
81 | .argval = -1, | |
82 | .help = N_("get discard zeroes support status") | |
c3f62be7 KZ |
83 | },{ |
84 | IOCTL_ENTRY(BLKSSZGET), | |
85 | .name = "--getss", | |
86 | .argtype = ARG_INT, | |
87 | .argval = -1, | |
d965d63f KZ |
88 | .help = N_("get logical block (sector) size") |
89 | },{ | |
90 | IOCTL_ENTRY(BLKPBSZGET), | |
91 | .name = "--getpbsz", | |
92 | .argtype = ARG_UINT, | |
93 | .argval = -1, | |
94 | .help = N_("get physical block (sector) size") | |
95 | },{ | |
96 | IOCTL_ENTRY(BLKIOMIN), | |
97 | .name = "--getiomin", | |
98 | .argtype = ARG_UINT, | |
99 | .argval = -1, | |
100 | .help = N_("get minimum I/O size") | |
101 | },{ | |
102 | IOCTL_ENTRY(BLKIOOPT), | |
103 | .name = "--getioopt", | |
104 | .argtype = ARG_UINT, | |
105 | .argval = -1, | |
106 | .help = N_("get optimal I/O size") | |
107 | },{ | |
108 | IOCTL_ENTRY(BLKALIGNOFF), | |
109 | .name = "--getalignoff", | |
110 | .argtype = ARG_INT, | |
ed98508a | 111 | .argval = -1, |
455fdf4a | 112 | .help = N_("get alignment offset in bytes") |
d965d63f KZ |
113 | },{ |
114 | IOCTL_ENTRY(BLKSECTGET), | |
115 | .name = "--getmaxsect", | |
116 | .argtype = ARG_USHRT, | |
117 | .argval = -1, | |
118 | .help = N_("get max sectors per request") | |
c3f62be7 KZ |
119 | },{ |
120 | IOCTL_ENTRY(BLKBSZGET), | |
121 | .name = "--getbsz", | |
122 | .argtype = ARG_INT, | |
123 | .argval = -1, | |
124 | .help = N_("get blocksize") | |
39d2e706 KZ |
125 | },{ |
126 | IOCTL_ENTRY(BLKBSZSET), | |
127 | .name = "--setbsz", | |
128 | .argname = "<bytes>", | |
129 | .argtype = ARG_INT, | |
130 | .flags = FL_NORESULT, | |
7ab32ae6 | 131 | .help = N_("set blocksize on file descriptor opening the block device") |
c3f62be7 KZ |
132 | },{ |
133 | IOCTL_ENTRY(BLKGETSIZE), | |
134 | .name = "--getsize", | |
135 | .argtype = ARG_ULONG, | |
136 | .argval = -1, | |
455fdf4a | 137 | .help = N_("get 32-bit sector count (deprecated, use --getsz)") |
c3f62be7 KZ |
138 | },{ |
139 | IOCTL_ENTRY(BLKGETSIZE64), | |
140 | .name = "--getsize64", | |
141 | .argtype = ARG_ULLONG, | |
142 | .argval = -1, | |
143 | .help = N_("get size in bytes") | |
144 | },{ | |
145 | IOCTL_ENTRY(BLKRASET), | |
146 | .name = "--setra", | |
455fdf4a | 147 | .argname = "<sectors>", |
c3f62be7 KZ |
148 | .argtype = ARG_INT, |
149 | .flags = FL_NOPTR | FL_NORESULT, | |
150 | .help = N_("set readahead") | |
151 | },{ | |
152 | IOCTL_ENTRY(BLKRAGET), | |
153 | .name = "--getra", | |
154 | .argtype = ARG_LONG, | |
155 | .argval = -1, | |
156 | .help = N_("get readahead") | |
157 | },{ | |
158 | IOCTL_ENTRY(BLKFRASET), | |
159 | .name = "--setfra", | |
455fdf4a | 160 | .argname = "<sectors>", |
c3f62be7 KZ |
161 | .argtype = ARG_INT, |
162 | .flags = FL_NOPTR | FL_NORESULT, | |
163 | .help = N_("set filesystem readahead") | |
164 | },{ | |
165 | IOCTL_ENTRY(BLKFRAGET), | |
166 | .name = "--getfra", | |
167 | .argtype = ARG_LONG, | |
168 | .argval = -1, | |
169 | .help = N_("get filesystem readahead") | |
170 | },{ | |
171 | IOCTL_ENTRY(BLKFLSBUF), | |
172 | .name = "--flushbufs", | |
173 | .help = N_("flush buffers") | |
174 | },{ | |
175 | IOCTL_ENTRY(BLKRRPART), | |
176 | .name = "--rereadpt", | |
177 | .help = N_("reread partition table") | |
178 | } | |
eb63b9b8 KZ |
179 | }; |
180 | ||
bded204c SK |
181 | static void __attribute__ ((__noreturn__)) usage(FILE * out) |
182 | { | |
75737ad6 | 183 | size_t i; |
bded204c | 184 | fprintf(out, _("\nUsage:\n" |
637775c7 KZ |
185 | " %1$s -V\n" |
186 | " %1$s --report [devices]\n" | |
187 | " %1$s [-v|-q] commands devices\n\n" | |
bded204c | 188 | "Available commands:\n"), program_invocation_short_name); |
a424171c | 189 | |
637775c7 | 190 | fprintf(out, _(" %-25s get size in 512-byte sectors\n"), "--getsz"); |
515422fd | 191 | for (i = 0; i < ARRAY_SIZE(bdcms); i++) { |
eb63b9b8 | 192 | if (bdcms[i].argname) |
637775c7 | 193 | fprintf(out, " %s %-*s %s\n", bdcms[i].name, |
bded204c SK |
194 | (int)(24 - strlen(bdcms[i].name)), |
195 | bdcms[i].argname, _(bdcms[i].help)); | |
a424171c | 196 | else |
637775c7 | 197 | fprintf(out, " %-25s %s\n", bdcms[i].name, |
bded204c | 198 | _(bdcms[i].help)); |
eb63b9b8 | 199 | } |
bded204c SK |
200 | fputc('\n', out); |
201 | exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); | |
eb63b9b8 KZ |
202 | } |
203 | ||
baaa4479 SK |
204 | static int find_cmd(char *s) |
205 | { | |
75737ad6 | 206 | size_t j; |
eb63b9b8 | 207 | |
515422fd | 208 | for (j = 0; j < ARRAY_SIZE(bdcms); j++) |
eb63b9b8 KZ |
209 | if (!strcmp(s, bdcms[j].name)) |
210 | return j; | |
211 | return -1; | |
212 | } | |
213 | ||
f61a097b WG |
214 | static void do_commands(int fd, char **argv, int d); |
215 | static void report_header(void); | |
216 | static void report_device(char *device, int quiet); | |
217 | static void report_all_devices(void); | |
eb63b9b8 | 218 | |
baaa4479 SK |
219 | int main(int argc, char **argv) |
220 | { | |
eb63b9b8 | 221 | int fd, d, j, k; |
eb63b9b8 | 222 | |
eb63b9b8 KZ |
223 | setlocale(LC_ALL, ""); |
224 | bindtextdomain(PACKAGE, LOCALEDIR); | |
225 | textdomain(PACKAGE); | |
45ca68ec | 226 | atexit(close_stdout); |
eb63b9b8 KZ |
227 | |
228 | if (argc < 2) | |
bded204c | 229 | usage(stderr); |
eb63b9b8 KZ |
230 | |
231 | /* -V not together with commands */ | |
232 | if (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")) { | |
e421313d | 233 | printf(UTIL_LINUX_VERSION); |
6b515d0b | 234 | return EXIT_SUCCESS; |
eb63b9b8 | 235 | } |
bded204c SK |
236 | if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) |
237 | usage(stdout); | |
eb63b9b8 | 238 | |
612721db KZ |
239 | /* --report not together with other commands */ |
240 | if (!strcmp(argv[1], "--report")) { | |
241 | report_header(); | |
242 | if (argc > 2) { | |
243 | for (d = 2; d < argc; d++) | |
244 | report_device(argv[d], 0); | |
245 | } else { | |
246 | report_all_devices(); | |
247 | } | |
6b515d0b | 248 | return EXIT_SUCCESS; |
612721db KZ |
249 | } |
250 | ||
eb63b9b8 KZ |
251 | /* do each of the commands on each of the devices */ |
252 | /* devices start after last command */ | |
253 | for (d = 1; d < argc; d++) { | |
254 | j = find_cmd(argv[d]); | |
255 | if (j >= 0) { | |
c3f62be7 | 256 | if (bdcms[j].argname) |
eb63b9b8 KZ |
257 | d++; |
258 | continue; | |
259 | } | |
c129767e KZ |
260 | if (!strcmp(argv[d], "--getsz")) |
261 | continue; | |
eb63b9b8 KZ |
262 | if (!strcmp(argv[d], "--")) { |
263 | d++; | |
264 | break; | |
265 | } | |
266 | if (argv[d][0] != '-') | |
267 | break; | |
268 | } | |
269 | ||
270 | if (d >= argc) | |
bded204c | 271 | usage(stderr); |
eb63b9b8 KZ |
272 | |
273 | for (k = d; k < argc; k++) { | |
274 | fd = open(argv[k], O_RDONLY, 0); | |
6b515d0b SK |
275 | if (fd < 0) |
276 | err(EXIT_FAILURE, _("cannot open %s"), argv[k]); | |
eb63b9b8 | 277 | do_commands(fd, argv, d); |
e8f26419 | 278 | close(fd); |
eb63b9b8 | 279 | } |
6b515d0b | 280 | return EXIT_SUCCESS; |
eb63b9b8 KZ |
281 | } |
282 | ||
f61a097b | 283 | static void do_commands(int fd, char **argv, int d) |
baaa4479 | 284 | { |
eb63b9b8 | 285 | int res, i, j; |
15705de0 KZ |
286 | int iarg = 0; |
287 | unsigned int uarg = 0; | |
288 | unsigned short huarg = 0; | |
289 | long larg = 0; | |
290 | long long llarg = 0; | |
291 | unsigned long lu = 0; | |
292 | unsigned long long llu = 0; | |
eb63b9b8 KZ |
293 | int verbose = 0; |
294 | ||
295 | for (i = 1; i < d; i++) { | |
296 | if (!strcmp(argv[i], "-v")) { | |
297 | verbose = 1; | |
298 | continue; | |
baaa4479 | 299 | } |
eb63b9b8 KZ |
300 | if (!strcmp(argv[i], "-q")) { |
301 | verbose = 0; | |
302 | continue; | |
303 | } | |
304 | ||
c129767e | 305 | if (!strcmp(argv[i], "--getsz")) { |
bc8b6383 | 306 | res = blkdev_get_sectors(fd, &llu); |
c129767e | 307 | if (res == 0) |
bc8b6383 | 308 | printf("%lld\n", llu); |
c129767e | 309 | else |
baaa4479 SK |
310 | errx(EXIT_FAILURE, |
311 | _("could not get device size")); | |
c129767e KZ |
312 | continue; |
313 | } | |
314 | ||
eb63b9b8 KZ |
315 | j = find_cmd(argv[i]); |
316 | if (j == -1) { | |
cc4d8d72 | 317 | warnx(_("Unknown command: %s"), argv[i]); |
bded204c | 318 | usage(stderr); |
eb63b9b8 KZ |
319 | } |
320 | ||
baaa4479 | 321 | switch (bdcms[j].argtype) { |
eb63b9b8 | 322 | default: |
c3f62be7 | 323 | case ARG_NONE: |
eb63b9b8 KZ |
324 | res = ioctl(fd, bdcms[j].ioc, 0); |
325 | break; | |
726fa24e KZ |
326 | case ARG_USHRT: |
327 | huarg = bdcms[j].argval; | |
328 | res = ioctl(fd, bdcms[j].ioc, &huarg); | |
329 | break; | |
c3f62be7 KZ |
330 | case ARG_INT: |
331 | if (bdcms[j].argname) { | |
baaa4479 | 332 | if (i == d - 1) { |
cc4d8d72 | 333 | warnx(_("%s requires an argument"), |
baaa4479 | 334 | bdcms[j].name); |
bded204c | 335 | usage(stderr); |
c3f62be7 KZ |
336 | } |
337 | iarg = atoi(argv[++i]); | |
338 | } else | |
339 | iarg = bdcms[j].argval; | |
340 | ||
341 | res = bdcms[j].flags & FL_NOPTR ? | |
baaa4479 SK |
342 | ioctl(fd, bdcms[j].ioc, iarg) : |
343 | ioctl(fd, bdcms[j].ioc, &iarg); | |
eb63b9b8 | 344 | break; |
726fa24e KZ |
345 | case ARG_UINT: |
346 | uarg = bdcms[j].argval; | |
347 | res = ioctl(fd, bdcms[j].ioc, &uarg); | |
348 | break; | |
c3f62be7 | 349 | case ARG_LONG: |
eb63b9b8 KZ |
350 | larg = bdcms[j].argval; |
351 | res = ioctl(fd, bdcms[j].ioc, &larg); | |
352 | break; | |
c3f62be7 | 353 | case ARG_LLONG: |
c129767e KZ |
354 | llarg = bdcms[j].argval; |
355 | res = ioctl(fd, bdcms[j].ioc, &llarg); | |
356 | break; | |
c3f62be7 | 357 | case ARG_ULONG: |
1dea05a8 KZ |
358 | lu = bdcms[j].argval; |
359 | res = ioctl(fd, bdcms[j].ioc, &lu); | |
360 | break; | |
c3f62be7 | 361 | case ARG_ULLONG: |
1dea05a8 KZ |
362 | llu = bdcms[j].argval; |
363 | res = ioctl(fd, bdcms[j].ioc, &llu); | |
364 | break; | |
eb63b9b8 | 365 | } |
c3f62be7 | 366 | |
eb63b9b8 | 367 | if (res == -1) { |
338a6bc5 | 368 | warn(_("ioctl error on %s"), bdcms[j].iocname); |
eb63b9b8 | 369 | if (verbose) |
65b27d36 | 370 | printf(_("%s failed.\n"), _(bdcms[j].help)); |
6b515d0b | 371 | exit(EXIT_FAILURE); |
eb63b9b8 | 372 | } |
c3f62be7 KZ |
373 | |
374 | if (bdcms[j].argtype == ARG_NONE || | |
375 | (bdcms[j].flags & FL_NORESULT)) { | |
eb63b9b8 | 376 | if (verbose) |
c3f62be7 KZ |
377 | printf(_("%s succeeded.\n"), _(bdcms[j].help)); |
378 | continue; | |
379 | } | |
380 | ||
381 | if (verbose) | |
382 | printf("%s: ", _(bdcms[j].help)); | |
383 | ||
baaa4479 | 384 | switch (bdcms[j].argtype) { |
726fa24e KZ |
385 | case ARG_USHRT: |
386 | printf("%hu\n", huarg); | |
387 | break; | |
c3f62be7 KZ |
388 | case ARG_INT: |
389 | printf("%d\n", iarg); | |
eb63b9b8 | 390 | break; |
726fa24e KZ |
391 | case ARG_UINT: |
392 | printf("%u\n", uarg); | |
393 | break; | |
c3f62be7 KZ |
394 | case ARG_LONG: |
395 | printf("%ld\n", larg); | |
c129767e | 396 | break; |
c3f62be7 KZ |
397 | case ARG_LLONG: |
398 | printf("%lld\n", llarg); | |
1dea05a8 | 399 | break; |
c3f62be7 KZ |
400 | case ARG_ULONG: |
401 | printf("%lu\n", lu); | |
1dea05a8 | 402 | break; |
c3f62be7 KZ |
403 | case ARG_ULLONG: |
404 | printf("%llu\n", llu); | |
eb63b9b8 KZ |
405 | break; |
406 | } | |
407 | } | |
408 | } | |
612721db | 409 | |
f61a097b | 410 | static void report_all_devices(void) |
baaa4479 | 411 | { |
612721db KZ |
412 | FILE *procpt; |
413 | char line[200]; | |
657d9adb | 414 | char ptname[200 + 1]; |
612721db KZ |
415 | char device[210]; |
416 | int ma, mi, sz; | |
417 | ||
14c76d8b | 418 | procpt = fopen(_PATH_PROC_PARTITIONS, "r"); |
cc4d8d72 | 419 | if (!procpt) |
14c76d8b | 420 | err(EXIT_FAILURE, _("cannot open %s"), _PATH_PROC_PARTITIONS); |
612721db KZ |
421 | |
422 | while (fgets(line, sizeof(line), procpt)) { | |
baaa4479 SK |
423 | if (sscanf(line, " %d %d %d %200[^\n ]", |
424 | &ma, &mi, &sz, ptname) != 4) | |
612721db KZ |
425 | continue; |
426 | ||
427 | sprintf(device, "/dev/%s", ptname); | |
428 | report_device(device, 1); | |
429 | } | |
122db55d | 430 | |
431 | fclose(procpt); | |
612721db KZ |
432 | } |
433 | ||
f61a097b | 434 | static void report_device(char *device, int quiet) |
baaa4479 | 435 | { |
612721db KZ |
436 | int fd; |
437 | int ro, ssz, bsz; | |
bc8b6383 KZ |
438 | long ra; |
439 | unsigned long long bytes; | |
569d1dac | 440 | uint64_t start = 0; |
569d1dac | 441 | struct stat st; |
612721db KZ |
442 | |
443 | fd = open(device, O_RDONLY | O_NONBLOCK); | |
444 | if (fd < 0) { | |
445 | if (!quiet) | |
6b515d0b | 446 | warn(_("cannot open %s"), device); |
612721db KZ |
447 | return; |
448 | } | |
449 | ||
450 | ro = ssz = bsz = 0; | |
569d1dac | 451 | ra = 0; |
95305cec KZ |
452 | if (fstat(fd, &st) == 0 && !sysfs_devno_is_wholedisk(st.st_rdev)) { |
453 | struct sysfs_cxt cxt; | |
454 | ||
569d1dac PS |
455 | if (sysfs_init(&cxt, st.st_rdev, NULL)) |
456 | err(EXIT_FAILURE, | |
457 | _("%s: failed to initialize sysfs handler"), | |
458 | device); | |
9eaa7292 KZ |
459 | if (sysfs_read_u64(&cxt, "start", &start)) |
460 | err(EXIT_FAILURE, | |
461 | _("%s: failed to read partition start from sysfs"), | |
462 | device); | |
569d1dac PS |
463 | sysfs_deinit(&cxt); |
464 | } | |
baaa4479 SK |
465 | if (ioctl(fd, BLKROGET, &ro) == 0 && |
466 | ioctl(fd, BLKRAGET, &ra) == 0 && | |
467 | ioctl(fd, BLKSSZGET, &ssz) == 0 && | |
468 | ioctl(fd, BLKBSZGET, &bsz) == 0 && | |
baaa4479 | 469 | blkdev_get_size(fd, &bytes) == 0) { |
569d1dac PS |
470 | printf("%s %5ld %5d %5d %10ju %15lld %s\n", |
471 | ro ? "ro" : "rw", ra, ssz, bsz, start, bytes, device); | |
612721db KZ |
472 | } else { |
473 | if (!quiet) | |
cc4d8d72 | 474 | warnx(_("ioctl error on %s"), device); |
612721db | 475 | } |
122db55d | 476 | |
477 | close(fd); | |
612721db KZ |
478 | } |
479 | ||
16bd8025 | 480 | static void report_header(void) |
baaa4479 | 481 | { |
bc8b6383 | 482 | printf(_("RO RA SSZ BSZ StartSec Size Device\n")); |
612721db | 483 | } |