2 * blockdev.c --- Do various simple block device ioctls from the command line
11 #include <sys/ioctl.h>
17 #include "pathnames.h"
18 #include "closestream.h"
23 long ioc
; /* ioctl code */
24 const char *iocname
; /* ioctl name (e.g. BLKROSET) */
25 long argval
; /* default argument */
27 const char *name
; /* --setfoo */
28 const char *argname
; /* argument name or NULL */
38 FL_NOPTR
= (1 << 1), /* does not assume pointer (ARG_INT only)*/
39 FL_NORESULT
= (1 << 2) /* does not return any data */
42 /* ioctl argument types */
54 #define IOCTL_ENTRY( io ) .ioc = io, .iocname = # io
56 static const struct bdc bdcms
[] =
59 IOCTL_ENTRY(BLKROSET
),
64 .help
= N_("set read-only")
66 IOCTL_ENTRY(BLKROSET
),
71 .help
= N_("set read-write")
73 IOCTL_ENTRY(BLKROGET
),
77 .help
= N_("get read-only")
79 IOCTL_ENTRY(BLKDISCARDZEROES
),
80 .name
= "--getdiscardzeroes",
83 .help
= N_("get discard zeroes support status")
85 IOCTL_ENTRY(BLKSSZGET
),
89 .help
= N_("get logical block (sector) size")
91 IOCTL_ENTRY(BLKPBSZGET
),
95 .help
= N_("get physical block (sector) size")
97 IOCTL_ENTRY(BLKIOMIN
),
101 .help
= N_("get minimum I/O size")
103 IOCTL_ENTRY(BLKIOOPT
),
104 .name
= "--getioopt",
107 .help
= N_("get optimal I/O size")
109 IOCTL_ENTRY(BLKALIGNOFF
),
110 .name
= "--getalignoff",
113 .help
= N_("get alignment offset in bytes")
115 IOCTL_ENTRY(BLKSECTGET
),
116 .name
= "--getmaxsect",
117 .argtype
= ARG_USHRT
,
119 .help
= N_("get max sectors per request")
121 IOCTL_ENTRY(BLKBSZGET
),
125 .help
= N_("get blocksize")
127 IOCTL_ENTRY(BLKBSZSET
),
129 .argname
= "<bytes>",
131 .flags
= FL_NORESULT
,
132 .help
= N_("set blocksize on file descriptor opening the block device")
134 IOCTL_ENTRY(BLKGETSIZE
),
136 .argtype
= ARG_ULONG
,
138 .help
= N_("get 32-bit sector count (deprecated, use --getsz)")
140 IOCTL_ENTRY(BLKGETSIZE64
),
141 .name
= "--getsize64",
142 .argtype
= ARG_ULLONG
,
144 .help
= N_("get size in bytes")
146 IOCTL_ENTRY(BLKRASET
),
148 .argname
= "<sectors>",
150 .flags
= FL_NOPTR
| FL_NORESULT
,
151 .help
= N_("set readahead")
153 IOCTL_ENTRY(BLKRAGET
),
157 .help
= N_("get readahead")
159 IOCTL_ENTRY(BLKFRASET
),
161 .argname
= "<sectors>",
163 .flags
= FL_NOPTR
| FL_NORESULT
,
164 .help
= N_("set filesystem readahead")
166 IOCTL_ENTRY(BLKFRAGET
),
170 .help
= N_("get filesystem readahead")
172 IOCTL_ENTRY(BLKGETDISKSEQ
),
173 .name
= "--getdiskseq",
174 .argtype
= ARG_ULLONG
,
176 .help
= N_("get disk sequence number")
178 IOCTL_ENTRY(BLKFLSBUF
),
179 .name
= "--flushbufs",
180 .help
= N_("flush buffers")
182 IOCTL_ENTRY(BLKRRPART
),
183 .name
= "--rereadpt",
184 .help
= N_("reread partition table")
188 static void __attribute__((__noreturn__
)) usage(void)
192 fputs(USAGE_HEADER
, stdout
);
194 " %1$s [-v|-q] commands devices\n"
195 " %1$s --report [devices]\n"
197 ), program_invocation_short_name
);
199 fputs(USAGE_SEPARATOR
, stdout
);
200 puts( _("Call block device ioctls from the command line."));
202 fputs(USAGE_OPTIONS
, stdout
);
203 puts( _(" -q quiet mode"));
204 puts( _(" -v verbose mode"));
205 puts( _(" --report print report for specified (or all) devices"));
206 fputs(USAGE_SEPARATOR
, stdout
);
207 printf(USAGE_HELP_OPTIONS(16));
209 fputs(USAGE_SEPARATOR
, stdout
);
210 puts( _("Available commands:"));
211 printf(_(" %-25s get size in 512-byte sectors\n"), "--getsz");
212 for (i
= 0; i
< ARRAY_SIZE(bdcms
); i
++) {
213 if (bdcms
[i
].argname
)
214 printf(" %s %-*s %s\n", bdcms
[i
].name
,
215 (int)(24 - strlen(bdcms
[i
].name
)),
216 bdcms
[i
].argname
, _(bdcms
[i
].help
));
218 printf(" %-25s %s\n", bdcms
[i
].name
,
222 printf(USAGE_MAN_TAIL("blockdev(8)"));
226 static int find_cmd(char *s
)
230 for (j
= 0; j
< ARRAY_SIZE(bdcms
); j
++)
231 if (!strcmp(s
, bdcms
[j
].name
))
236 static void do_commands(int fd
, char **argv
, int d
);
237 static void report_header(void);
238 static void report_device(char *device
, int quiet
);
239 static void report_all_devices(void);
241 int main(int argc
, char **argv
)
245 setlocale(LC_ALL
, "");
246 bindtextdomain(PACKAGE
, LOCALEDIR
);
248 close_stdout_atexit();
251 warnx(_("not enough arguments"));
252 errtryhelp(EXIT_FAILURE
);
255 /* -V not together with commands */
256 if (!strcmp(argv
[1], "-V") || !strcmp(argv
[1], "--version"))
257 print_version(EXIT_SUCCESS
);
258 if (!strcmp(argv
[1], "-h") || !strcmp(argv
[1], "--help"))
261 /* --report not together with other commands */
262 if (!strcmp(argv
[1], "--report")) {
265 for (d
= 2; d
< argc
; d
++)
266 report_device(argv
[d
], 0);
268 report_all_devices();
273 /* do each of the commands on each of the devices */
274 /* devices start after last command */
275 for (d
= 1; d
< argc
; d
++) {
276 j
= find_cmd(argv
[d
]);
278 if (bdcms
[j
].argname
)
282 if (!strcmp(argv
[d
], "--getsz"))
284 if (!strcmp(argv
[d
], "--")) {
288 if (argv
[d
][0] != '-')
293 warnx(_("no device specified"));
294 errtryhelp(EXIT_FAILURE
);
297 for (k
= d
; k
< argc
; k
++) {
298 fd
= open(argv
[k
], O_RDONLY
, 0);
300 err(EXIT_FAILURE
, _("cannot open %s"), argv
[k
]);
301 do_commands(fd
, argv
, d
);
307 static void do_commands(int fd
, char **argv
, int d
)
311 unsigned int uarg
= 0;
312 unsigned short huarg
= 0;
315 unsigned long lu
= 0;
316 unsigned long long llu
= 0;
319 for (i
= 1; i
< d
; i
++) {
320 if (!strcmp(argv
[i
], "-v")) {
324 if (!strcmp(argv
[i
], "-q")) {
329 if (!strcmp(argv
[i
], "--getsz")) {
330 res
= blkdev_get_sectors(fd
, &llu
);
332 printf("%lld\n", llu
);
335 _("could not get device size"));
339 j
= find_cmd(argv
[i
]);
341 warnx(_("Unknown command: %s"), argv
[i
]);
342 errtryhelp(EXIT_FAILURE
);
345 switch (bdcms
[j
].argtype
) {
348 res
= ioctl(fd
, bdcms
[j
].ioc
, 0);
351 huarg
= bdcms
[j
].argval
;
352 res
= ioctl(fd
, bdcms
[j
].ioc
, &huarg
);
355 if (bdcms
[j
].argname
) {
357 warnx(_("%s requires an argument"),
359 errtryhelp(EXIT_FAILURE
);
361 iarg
= strtos32_or_err(argv
[++i
], _("failed to parse command argument"));
363 iarg
= bdcms
[j
].argval
;
365 res
= bdcms
[j
].flags
& FL_NOPTR
?
366 ioctl(fd
, bdcms
[j
].ioc
, iarg
) :
367 ioctl(fd
, bdcms
[j
].ioc
, &iarg
);
370 uarg
= bdcms
[j
].argval
;
371 res
= ioctl(fd
, bdcms
[j
].ioc
, &uarg
);
374 larg
= bdcms
[j
].argval
;
375 res
= ioctl(fd
, bdcms
[j
].ioc
, &larg
);
378 llarg
= bdcms
[j
].argval
;
379 res
= ioctl(fd
, bdcms
[j
].ioc
, &llarg
);
382 lu
= bdcms
[j
].argval
;
383 res
= ioctl(fd
, bdcms
[j
].ioc
, &lu
);
386 llu
= bdcms
[j
].argval
;
387 res
= ioctl(fd
, bdcms
[j
].ioc
, &llu
);
392 warn(_("ioctl error on %s"), bdcms
[j
].iocname
);
394 printf(_("%s failed.\n"), _(bdcms
[j
].help
));
398 if (bdcms
[j
].argtype
== ARG_NONE
||
399 (bdcms
[j
].flags
& FL_NORESULT
)) {
401 printf(_("%s succeeded.\n"), _(bdcms
[j
].help
));
406 printf("%s: ", _(bdcms
[j
].help
));
408 switch (bdcms
[j
].argtype
) {
410 printf("%hu\n", huarg
);
413 printf("%d\n", iarg
);
416 printf("%u\n", uarg
);
419 printf("%ld\n", larg
);
422 printf("%lld\n", llarg
);
428 printf("%llu\n", llu
);
434 static void report_all_devices(void)
438 char ptname
[200 + 1];
442 procpt
= fopen(_PATH_PROC_PARTITIONS
, "r");
444 err(EXIT_FAILURE
, _("cannot open %s"), _PATH_PROC_PARTITIONS
);
446 while (fgets(line
, sizeof(line
), procpt
)) {
447 if (sscanf(line
, " %d %d %d %200[^\n ]",
448 &ma
, &mi
, &sz
, ptname
) != 4)
451 snprintf(device
, sizeof(device
), "/dev/%s", ptname
);
452 report_device(device
, 1);
458 static void report_device(char *device
, int quiet
)
463 unsigned long long bytes
;
465 char start_str
[16] = { "\0" };
468 fd
= open(device
, O_RDONLY
| O_NONBLOCK
);
471 warn(_("cannot open %s"), device
);
477 if (fstat(fd
, &st
) == 0) {
481 pc
= ul_new_sysfs_path(st
.st_rdev
, NULL
, NULL
);
483 sysfs_blkdev_get_wholedisk(pc
, NULL
, 0, &disk
) == 0 &&
484 disk
!= st
.st_rdev
) {
486 if (ul_path_read_u64(pc
, &start
, "start") != 0)
487 /* TRANSLATORS: Start sector not available. Max. 15 letters. */
488 snprintf(start_str
, sizeof(start_str
), "%15s", _("N/A"));
493 snprintf(start_str
, sizeof(start_str
), "%15ju", start
);
495 if (ioctl(fd
, BLKROGET
, &ro
) == 0 &&
496 ioctl(fd
, BLKRAGET
, &ra
) == 0 &&
497 ioctl(fd
, BLKSSZGET
, &ssz
) == 0 &&
498 ioctl(fd
, BLKBSZGET
, &bsz
) == 0 &&
499 blkdev_get_size(fd
, &bytes
) == 0) {
500 printf("%s %5ld %5d %5d %s %15lld %s\n",
501 ro
? "ro" : "rw", ra
, ssz
, bsz
, start_str
, bytes
, device
);
504 warnx(_("ioctl error on %s"), device
);
510 static void report_header(void)
512 printf(_("RO RA SSZ BSZ StartSec Size Device\n"));