2 * blockdev.c --- Do various simple block device ioctls from the command line
11 #include <sys/ioctl.h>
13 #ifdef HAVE_LINUX_BLKZONED_H
14 #include <linux/blkzoned.h>
20 #include "pathnames.h"
21 #include "closestream.h"
26 long ioc
; /* ioctl code */
27 const char *iocname
; /* ioctl name (e.g. BLKROSET) */
28 long argval
; /* default argument */
30 const char *name
; /* --setfoo */
31 const char *argname
; /* argument name or NULL */
41 FL_NOPTR
= (1 << 1), /* does not assume pointer (ARG_INT only)*/
42 FL_NORESULT
= (1 << 2) /* does not return any data */
45 /* ioctl argument types */
57 #define IOCTL_ENTRY( io ) .ioc = io, .iocname = # io
59 static const struct bdc bdcms
[] =
62 IOCTL_ENTRY(BLKROSET
),
67 .help
= N_("set read-only")
69 IOCTL_ENTRY(BLKROSET
),
74 .help
= N_("set read-write")
76 IOCTL_ENTRY(BLKROGET
),
80 .help
= N_("get read-only")
82 IOCTL_ENTRY(BLKDISCARDZEROES
),
83 .name
= "--getdiscardzeroes",
86 .help
= N_("get discard zeroes support status")
88 IOCTL_ENTRY(BLKSSZGET
),
92 .help
= N_("get logical block (sector) size")
94 IOCTL_ENTRY(BLKPBSZGET
),
98 .help
= N_("get physical block (sector) size")
100 IOCTL_ENTRY(BLKIOMIN
),
101 .name
= "--getiomin",
104 .help
= N_("get minimum I/O size")
106 IOCTL_ENTRY(BLKIOOPT
),
107 .name
= "--getioopt",
110 .help
= N_("get optimal I/O size")
112 IOCTL_ENTRY(BLKALIGNOFF
),
113 .name
= "--getalignoff",
116 .help
= N_("get alignment offset in bytes")
118 IOCTL_ENTRY(BLKSECTGET
),
119 .name
= "--getmaxsect",
120 .argtype
= ARG_USHRT
,
122 .help
= N_("get max sectors per request")
124 IOCTL_ENTRY(BLKBSZGET
),
128 .help
= N_("get blocksize")
130 IOCTL_ENTRY(BLKBSZSET
),
132 .argname
= "<bytes>",
134 .flags
= FL_NORESULT
,
135 .help
= N_("set blocksize on file descriptor opening the block device")
137 IOCTL_ENTRY(BLKGETSIZE
),
139 .argtype
= ARG_ULONG
,
141 .help
= N_("get 32-bit sector count (deprecated, use --getsz)")
143 IOCTL_ENTRY(BLKGETSIZE64
),
144 .name
= "--getsize64",
145 .argtype
= ARG_ULLONG
,
147 .help
= N_("get size in bytes")
149 IOCTL_ENTRY(BLKRASET
),
151 .argname
= "<sectors>",
153 .flags
= FL_NOPTR
| FL_NORESULT
,
154 .help
= N_("set readahead")
156 IOCTL_ENTRY(BLKRAGET
),
160 .help
= N_("get readahead")
162 IOCTL_ENTRY(BLKFRASET
),
164 .argname
= "<sectors>",
166 .flags
= FL_NOPTR
| FL_NORESULT
,
167 .help
= N_("set filesystem readahead")
169 IOCTL_ENTRY(BLKFRAGET
),
173 .help
= N_("get filesystem readahead")
175 IOCTL_ENTRY(BLKGETDISKSEQ
),
176 .name
= "--getdiskseq",
177 .argtype
= ARG_ULLONG
,
179 .help
= N_("get disk sequence number")
181 #ifdef HAVE_LINUX_BLKZONED_H
182 IOCTL_ENTRY(BLKGETZONESZ
),
183 .name
= "--getzonesz",
186 .help
= N_("get zone size")
189 IOCTL_ENTRY(BLKFLSBUF
),
190 .name
= "--flushbufs",
191 .help
= N_("flush buffers")
193 IOCTL_ENTRY(BLKRRPART
),
194 .name
= "--rereadpt",
195 .help
= N_("reread partition table")
199 static void __attribute__((__noreturn__
)) usage(void)
203 fputs(USAGE_HEADER
, stdout
);
205 " %1$s [-v|-q] commands devices\n"
206 " %1$s --report [devices]\n"
208 ), program_invocation_short_name
);
210 fputs(USAGE_SEPARATOR
, stdout
);
211 puts( _("Call block device ioctls from the command line."));
213 fputs(USAGE_OPTIONS
, stdout
);
214 puts( _(" -q quiet mode"));
215 puts( _(" -v verbose mode"));
216 puts( _(" --report print report for specified (or all) devices"));
217 fputs(USAGE_SEPARATOR
, stdout
);
218 printf(USAGE_HELP_OPTIONS(16));
220 fputs(USAGE_SEPARATOR
, stdout
);
221 puts( _("Available commands:"));
222 printf(_(" %-25s get size in 512-byte sectors\n"), "--getsz");
223 for (i
= 0; i
< ARRAY_SIZE(bdcms
); i
++) {
224 if (bdcms
[i
].argname
)
225 printf(" %s %-*s %s\n", bdcms
[i
].name
,
226 (int)(24 - strlen(bdcms
[i
].name
)),
227 bdcms
[i
].argname
, _(bdcms
[i
].help
));
229 printf(" %-25s %s\n", bdcms
[i
].name
,
233 printf(USAGE_MAN_TAIL("blockdev(8)"));
237 static int find_cmd(char *s
)
241 for (j
= 0; j
< ARRAY_SIZE(bdcms
); j
++)
242 if (!strcmp(s
, bdcms
[j
].name
))
247 static void do_commands(int fd
, char **argv
, int d
);
248 static void report_header(void);
249 static void report_device(char *device
, int quiet
);
250 static void report_all_devices(void);
252 int main(int argc
, char **argv
)
256 setlocale(LC_ALL
, "");
257 bindtextdomain(PACKAGE
, LOCALEDIR
);
259 close_stdout_atexit();
262 warnx(_("not enough arguments"));
263 errtryhelp(EXIT_FAILURE
);
266 /* -V not together with commands */
267 if (!strcmp(argv
[1], "-V") || !strcmp(argv
[1], "--version"))
268 print_version(EXIT_SUCCESS
);
269 if (!strcmp(argv
[1], "-h") || !strcmp(argv
[1], "--help"))
272 /* --report not together with other commands */
273 if (!strcmp(argv
[1], "--report")) {
276 for (d
= 2; d
< argc
; d
++)
277 report_device(argv
[d
], 0);
279 report_all_devices();
284 /* do each of the commands on each of the devices */
285 /* devices start after last command */
286 for (d
= 1; d
< argc
; d
++) {
287 j
= find_cmd(argv
[d
]);
289 if (bdcms
[j
].argname
)
293 if (!strcmp(argv
[d
], "--getsz"))
295 if (!strcmp(argv
[d
], "--")) {
299 if (argv
[d
][0] != '-')
304 warnx(_("no device specified"));
305 errtryhelp(EXIT_FAILURE
);
308 for (k
= d
; k
< argc
; k
++) {
309 fd
= open(argv
[k
], O_RDONLY
, 0);
311 err(EXIT_FAILURE
, _("cannot open %s"), argv
[k
]);
312 do_commands(fd
, argv
, d
);
318 static void do_commands(int fd
, char **argv
, int d
)
322 unsigned int uarg
= 0;
323 unsigned short huarg
= 0;
326 unsigned long lu
= 0;
327 unsigned long long llu
= 0;
330 for (i
= 1; i
< d
; i
++) {
331 if (!strcmp(argv
[i
], "-v")) {
335 if (!strcmp(argv
[i
], "-q")) {
340 if (!strcmp(argv
[i
], "--getsz")) {
341 res
= blkdev_get_sectors(fd
, &llu
);
343 printf("%lld\n", llu
);
346 _("could not get device size"));
350 j
= find_cmd(argv
[i
]);
352 warnx(_("Unknown command: %s"), argv
[i
]);
353 errtryhelp(EXIT_FAILURE
);
356 switch (bdcms
[j
].argtype
) {
359 res
= ioctl(fd
, bdcms
[j
].ioc
, 0);
362 huarg
= bdcms
[j
].argval
;
363 res
= ioctl(fd
, bdcms
[j
].ioc
, &huarg
);
366 if (bdcms
[j
].argname
) {
368 warnx(_("%s requires an argument"),
370 errtryhelp(EXIT_FAILURE
);
372 iarg
= strtos32_or_err(argv
[++i
], _("failed to parse command argument"));
374 iarg
= bdcms
[j
].argval
;
376 res
= bdcms
[j
].flags
& FL_NOPTR
?
377 ioctl(fd
, bdcms
[j
].ioc
, iarg
) :
378 ioctl(fd
, bdcms
[j
].ioc
, &iarg
);
381 uarg
= bdcms
[j
].argval
;
382 res
= ioctl(fd
, bdcms
[j
].ioc
, &uarg
);
385 larg
= bdcms
[j
].argval
;
386 res
= ioctl(fd
, bdcms
[j
].ioc
, &larg
);
389 llarg
= bdcms
[j
].argval
;
390 res
= ioctl(fd
, bdcms
[j
].ioc
, &llarg
);
393 lu
= bdcms
[j
].argval
;
394 res
= ioctl(fd
, bdcms
[j
].ioc
, &lu
);
397 llu
= bdcms
[j
].argval
;
398 res
= ioctl(fd
, bdcms
[j
].ioc
, &llu
);
403 warn(_("ioctl error on %s"), bdcms
[j
].iocname
);
405 printf(_("%s failed.\n"), _(bdcms
[j
].help
));
409 if (bdcms
[j
].argtype
== ARG_NONE
||
410 (bdcms
[j
].flags
& FL_NORESULT
)) {
412 printf(_("%s succeeded.\n"), _(bdcms
[j
].help
));
417 printf("%s: ", _(bdcms
[j
].help
));
419 switch (bdcms
[j
].argtype
) {
421 printf("%hu\n", huarg
);
424 printf("%d\n", iarg
);
427 printf("%u\n", uarg
);
430 printf("%ld\n", larg
);
433 printf("%lld\n", llarg
);
439 printf("%llu\n", llu
);
445 static void report_all_devices(void)
449 char ptname
[200 + 1];
453 procpt
= fopen(_PATH_PROC_PARTITIONS
, "r");
455 err(EXIT_FAILURE
, _("cannot open %s"), _PATH_PROC_PARTITIONS
);
457 while (fgets(line
, sizeof(line
), procpt
)) {
458 if (sscanf(line
, " %d %d %d %200[^\n ]",
459 &ma
, &mi
, &sz
, ptname
) != 4)
462 snprintf(device
, sizeof(device
), "/dev/%s", ptname
);
463 report_device(device
, 1);
469 static void report_device(char *device
, int quiet
)
474 unsigned long long bytes
;
476 char start_str
[16] = { "\0" };
479 fd
= open(device
, O_RDONLY
| O_NONBLOCK
);
482 warn(_("cannot open %s"), device
);
488 if (fstat(fd
, &st
) == 0) {
492 pc
= ul_new_sysfs_path(st
.st_rdev
, NULL
, NULL
);
494 sysfs_blkdev_get_wholedisk(pc
, NULL
, 0, &disk
) == 0 &&
495 disk
!= st
.st_rdev
) {
497 if (ul_path_read_u64(pc
, &start
, "start") != 0)
498 /* TRANSLATORS: Start sector not available. Max. 15 letters. */
499 snprintf(start_str
, sizeof(start_str
), "%15s", _("N/A"));
504 snprintf(start_str
, sizeof(start_str
), "%15ju", start
);
506 if (ioctl(fd
, BLKROGET
, &ro
) == 0 &&
507 ioctl(fd
, BLKRAGET
, &ra
) == 0 &&
508 ioctl(fd
, BLKSSZGET
, &ssz
) == 0 &&
509 ioctl(fd
, BLKBSZGET
, &bsz
) == 0 &&
510 blkdev_get_size(fd
, &bytes
) == 0) {
511 printf("%s %5ld %5d %5d %s %15lld %s\n",
512 ro
? "ro" : "rw", ra
, ssz
, bsz
, start_str
, bytes
, device
);
515 warnx(_("ioctl error on %s"), device
);
521 static void report_header(void)
523 printf(_("RO RA SSZ BSZ StartSec Size Device\n"));