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