2 * blockdev.c --- Do various simple block device ioctls from the command line
11 #include <sys/ioctl.h>
17 #include "pathnames.h"
20 long ioc; /* ioctl code */
21 const char *iocname; /* ioctl name (e.g. BLKROSET) */
22 long argval; /* default argument */
24 const char *name; /* --setfoo */
25 const char *argname; /* argument name or NULL */
35 FL_NOPTR = (1 << 1), /* does not assume pointer (ARG_INT only)*/
36 FL_NORESULT = (1 << 2) /* does not return any data */
39 /* ioctl argument types */
51 #define IOCTL_ENTRY( io ) .ioc = io, .iocname = # io
53 static const struct bdc bdcms[] =
56 IOCTL_ENTRY(BLKROSET),
61 .help = N_("set read-only")
63 IOCTL_ENTRY(BLKROSET),
68 .help = N_("set read-write")
70 IOCTL_ENTRY(BLKROGET),
74 .help = N_("get read-only")
76 IOCTL_ENTRY(BLKDISCARDZEROES),
77 .name = "--getdiscardzeroes",
80 .help = N_("get discard zeroes support status")
82 IOCTL_ENTRY(BLKSSZGET),
86 .help = N_("get logical block (sector) size")
88 IOCTL_ENTRY(BLKPBSZGET),
92 .help = N_("get physical block (sector) size")
94 IOCTL_ENTRY(BLKIOMIN),
98 .help = N_("get minimum I/O size")
100 IOCTL_ENTRY(BLKIOOPT),
101 .name = "--getioopt",
104 .help = N_("get optimal I/O size")
106 IOCTL_ENTRY(BLKALIGNOFF),
107 .name = "--getalignoff",
110 .help = N_("get alignment offset in bytes")
112 IOCTL_ENTRY(BLKSECTGET),
113 .name = "--getmaxsect",
114 .argtype = ARG_USHRT,
116 .help = N_("get max sectors per request")
118 IOCTL_ENTRY(BLKBSZGET),
122 .help = N_("get blocksize")
124 IOCTL_ENTRY(BLKBSZSET),
126 .argname = "<bytes>",
128 .flags = FL_NORESULT,
129 .help = N_("set blocksize")
131 IOCTL_ENTRY(BLKGETSIZE),
133 .argtype = ARG_ULONG,
135 .help = N_("get 32-bit sector count (deprecated, use --getsz)")
137 IOCTL_ENTRY(BLKGETSIZE64),
138 .name = "--getsize64",
139 .argtype = ARG_ULLONG,
141 .help = N_("get size in bytes")
143 IOCTL_ENTRY(BLKRASET),
145 .argname = "<sectors>",
147 .flags = FL_NOPTR | FL_NORESULT,
148 .help = N_("set readahead")
150 IOCTL_ENTRY(BLKRAGET),
154 .help = N_("get readahead")
156 IOCTL_ENTRY(BLKFRASET),
158 .argname = "<sectors>",
160 .flags = FL_NOPTR | FL_NORESULT,
161 .help = N_("set filesystem readahead")
163 IOCTL_ENTRY(BLKFRAGET),
167 .help = N_("get filesystem readahead")
169 IOCTL_ENTRY(BLKFLSBUF),
170 .name = "--flushbufs",
171 .help = N_("flush buffers")
173 IOCTL_ENTRY(BLKRRPART),
174 .name = "--rereadpt",
175 .help = N_("reread partition table")
179 static void __attribute__ ((__noreturn__)) usage(FILE * out)
182 fprintf(out, _("\nUsage:\n"
184 " %1$s --report [devices]\n"
185 " %1$s [-v|-q] commands devices\n\n"
186 "Available commands:\n"), program_invocation_short_name);
188 fprintf(out, _(" %-25s get size in 512-byte sectors\n"), "--getsz");
189 for (i = 0; i < ARRAY_SIZE(bdcms); i++) {
190 if (bdcms[i].argname)
191 fprintf(out, " %s %-*s %s\n", bdcms[i].name,
192 (int)(24 - strlen(bdcms[i].name)),
193 bdcms[i].argname, _(bdcms[i].help));
195 fprintf(out, " %-25s %s\n", bdcms[i].name,
199 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
202 static int find_cmd(char *s)
206 for (j = 0; j < ARRAY_SIZE(bdcms); j++)
207 if (!strcmp(s, bdcms[j].name))
212 void do_commands(int fd, char **argv, int d);
213 void report_header(void);
214 void report_device(char *device, int quiet);
215 void report_all_devices(void);
217 int main(int argc, char **argv)
221 setlocale(LC_ALL, "");
222 bindtextdomain(PACKAGE, LOCALEDIR);
228 /* -V not together with commands */
229 if (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")) {
230 printf(_("%s (%s)\n"), program_invocation_short_name,
234 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
237 /* --report not together with other commands */
238 if (!strcmp(argv[1], "--report")) {
241 for (d = 2; d < argc; d++)
242 report_device(argv[d], 0);
244 report_all_devices();
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]);
254 if (bdcms[j].argname)
258 if (!strcmp(argv[d], "--getsz"))
260 if (!strcmp(argv[d], "--")) {
264 if (argv[d][0] != '-')
271 for (k = d; k < argc; k++) {
272 fd = open(argv[k], O_RDONLY, 0);
274 err(EXIT_FAILURE, _("cannot open %s"), argv[k]);
275 do_commands(fd, argv, d);
281 void do_commands(int fd, char **argv, int d)
286 unsigned short huarg;
290 unsigned long long llu;
293 for (i = 1; i < d; i++) {
294 if (!strcmp(argv[i], "-v")) {
298 if (!strcmp(argv[i], "-q")) {
303 if (!strcmp(argv[i], "--getsz")) {
304 res = blkdev_get_sectors(fd, &llu);
306 printf("%lld\n", llu);
309 _("could not get device size"));
313 j = find_cmd(argv[i]);
315 warnx(_("Unknown command: %s"), argv[i]);
319 switch (bdcms[j].argtype) {
322 res = ioctl(fd, bdcms[j].ioc, 0);
325 huarg = bdcms[j].argval;
326 res = ioctl(fd, bdcms[j].ioc, &huarg);
329 if (bdcms[j].argname) {
331 warnx(_("%s requires an argument"),
335 iarg = atoi(argv[++i]);
337 iarg = bdcms[j].argval;
339 res = bdcms[j].flags & FL_NOPTR ?
340 ioctl(fd, bdcms[j].ioc, iarg) :
341 ioctl(fd, bdcms[j].ioc, &iarg);
344 uarg = bdcms[j].argval;
345 res = ioctl(fd, bdcms[j].ioc, &uarg);
348 larg = bdcms[j].argval;
349 res = ioctl(fd, bdcms[j].ioc, &larg);
352 llarg = bdcms[j].argval;
353 res = ioctl(fd, bdcms[j].ioc, &llarg);
356 lu = bdcms[j].argval;
357 res = ioctl(fd, bdcms[j].ioc, &lu);
360 llu = bdcms[j].argval;
361 res = ioctl(fd, bdcms[j].ioc, &llu);
366 perror(bdcms[j].iocname);
368 printf(_("%s failed.\n"), _(bdcms[j].help));
372 if (bdcms[j].argtype == ARG_NONE ||
373 (bdcms[j].flags & FL_NORESULT)) {
375 printf(_("%s succeeded.\n"), _(bdcms[j].help));
380 printf("%s: ", _(bdcms[j].help));
382 switch (bdcms[j].argtype) {
384 printf("%hu\n", huarg);
387 printf("%d\n", iarg);
390 printf("%u\n", uarg);
393 printf("%ld\n", larg);
396 printf("%lld\n", llarg);
402 printf("%llu\n", llu);
408 void report_all_devices(void)
416 procpt = fopen(_PATH_PROC_PARTITIONS, "r");
418 err(EXIT_FAILURE, _("cannot open %s"), _PATH_PROC_PARTITIONS);
420 while (fgets(line, sizeof(line), procpt)) {
421 if (sscanf(line, " %d %d %d %200[^\n ]",
422 &ma, &mi, &sz, ptname) != 4)
425 sprintf(device, "/dev/%s", ptname);
426 report_device(device, 1);
432 void report_device(char *device, int quiet)
437 unsigned long long bytes;
438 struct hd_geometry g;
440 fd = open(device, O_RDONLY | O_NONBLOCK);
443 warn(_("cannot open %s"), device);
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) {
455 printf("%s %5ld %5d %5d %10ld %15lld %s\n",
456 ro ? "ro" : "rw", ra, ssz, bsz, g.start, bytes, device);
459 warnx(_("ioctl error on %s"), device);
467 printf(_("RO RA SSZ BSZ StartSec Size Device\n"));