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"
22 long ioc
; /* ioctl code */
23 const char *iocname
; /* ioctl name (e.g. BLKROSET) */
24 long argval
; /* default argument */
26 const char *name
; /* --setfoo */
27 const char *argname
; /* argument name or NULL */
37 FL_NOPTR
= (1 << 1), /* does not assume pointer (ARG_INT only)*/
38 FL_NORESULT
= (1 << 2) /* does not return any data */
41 /* ioctl argument types */
53 #define IOCTL_ENTRY( io ) .ioc = io, .iocname = # io
55 static const struct bdc bdcms
[] =
58 IOCTL_ENTRY(BLKROSET
),
63 .help
= N_("set read-only")
65 IOCTL_ENTRY(BLKROSET
),
70 .help
= N_("set read-write")
72 IOCTL_ENTRY(BLKROGET
),
76 .help
= N_("get read-only")
78 IOCTL_ENTRY(BLKDISCARDZEROES
),
79 .name
= "--getdiscardzeroes",
82 .help
= N_("get discard zeroes support status")
84 IOCTL_ENTRY(BLKSSZGET
),
88 .help
= N_("get logical block (sector) size")
90 IOCTL_ENTRY(BLKPBSZGET
),
94 .help
= N_("get physical block (sector) size")
96 IOCTL_ENTRY(BLKIOMIN
),
100 .help
= N_("get minimum I/O size")
102 IOCTL_ENTRY(BLKIOOPT
),
103 .name
= "--getioopt",
106 .help
= N_("get optimal I/O size")
108 IOCTL_ENTRY(BLKALIGNOFF
),
109 .name
= "--getalignoff",
112 .help
= N_("get alignment offset in bytes")
114 IOCTL_ENTRY(BLKSECTGET
),
115 .name
= "--getmaxsect",
116 .argtype
= ARG_USHRT
,
118 .help
= N_("get max sectors per request")
120 IOCTL_ENTRY(BLKBSZGET
),
124 .help
= N_("get blocksize")
126 IOCTL_ENTRY(BLKBSZSET
),
128 .argname
= "<bytes>",
130 .flags
= FL_NORESULT
,
131 .help
= N_("set blocksize on file descriptor opening the block device")
133 IOCTL_ENTRY(BLKGETSIZE
),
135 .argtype
= ARG_ULONG
,
137 .help
= N_("get 32-bit sector count (deprecated, use --getsz)")
139 IOCTL_ENTRY(BLKGETSIZE64
),
140 .name
= "--getsize64",
141 .argtype
= ARG_ULLONG
,
143 .help
= N_("get size in bytes")
145 IOCTL_ENTRY(BLKRASET
),
147 .argname
= "<sectors>",
149 .flags
= FL_NOPTR
| FL_NORESULT
,
150 .help
= N_("set readahead")
152 IOCTL_ENTRY(BLKRAGET
),
156 .help
= N_("get readahead")
158 IOCTL_ENTRY(BLKFRASET
),
160 .argname
= "<sectors>",
162 .flags
= FL_NOPTR
| FL_NORESULT
,
163 .help
= N_("set filesystem readahead")
165 IOCTL_ENTRY(BLKFRAGET
),
169 .help
= N_("get filesystem readahead")
171 IOCTL_ENTRY(BLKFLSBUF
),
172 .name
= "--flushbufs",
173 .help
= N_("flush buffers")
175 IOCTL_ENTRY(BLKRRPART
),
176 .name
= "--rereadpt",
177 .help
= N_("reread partition table")
181 static void __attribute__((__noreturn__
)) usage(void)
185 fputs(USAGE_HEADER
, stdout
);
187 " %1$s [-v|-q] commands devices\n"
188 " %1$s --report [devices]\n"
190 ), program_invocation_short_name
);
192 fputs(USAGE_SEPARATOR
, stdout
);
193 puts( _("Call block device ioctls from the command line."));
195 fputs(USAGE_OPTIONS
, stdout
);
196 puts( _(" -q quiet mode"));
197 puts( _(" -v verbose mode"));
198 puts( _(" --report print report for specified (or all) devices"));
199 fputs(USAGE_SEPARATOR
, stdout
);
200 printf(USAGE_HELP_OPTIONS(16));
202 fputs(USAGE_SEPARATOR
, stdout
);
203 puts( _("Available commands:"));
204 printf(_(" %-25s get size in 512-byte sectors\n"), "--getsz");
205 for (i
= 0; i
< ARRAY_SIZE(bdcms
); i
++) {
206 if (bdcms
[i
].argname
)
207 printf(" %s %-*s %s\n", bdcms
[i
].name
,
208 (int)(24 - strlen(bdcms
[i
].name
)),
209 bdcms
[i
].argname
, _(bdcms
[i
].help
));
211 printf(" %-25s %s\n", bdcms
[i
].name
,
215 printf(USAGE_MAN_TAIL("blockdev(8)"));
219 static int find_cmd(char *s
)
223 for (j
= 0; j
< ARRAY_SIZE(bdcms
); j
++)
224 if (!strcmp(s
, bdcms
[j
].name
))
229 static void do_commands(int fd
, char **argv
, int d
);
230 static void report_header(void);
231 static void report_device(char *device
, int quiet
);
232 static void report_all_devices(void);
234 int main(int argc
, char **argv
)
238 setlocale(LC_ALL
, "");
239 bindtextdomain(PACKAGE
, LOCALEDIR
);
241 close_stdout_atexit();
244 warnx(_("not enough arguments"));
245 errtryhelp(EXIT_FAILURE
);
248 /* -V not together with commands */
249 if (!strcmp(argv
[1], "-V") || !strcmp(argv
[1], "--version"))
250 print_version(EXIT_SUCCESS
);
251 if (!strcmp(argv
[1], "-h") || !strcmp(argv
[1], "--help"))
254 /* --report not together with other commands */
255 if (!strcmp(argv
[1], "--report")) {
258 for (d
= 2; d
< argc
; d
++)
259 report_device(argv
[d
], 0);
261 report_all_devices();
266 /* do each of the commands on each of the devices */
267 /* devices start after last command */
268 for (d
= 1; d
< argc
; d
++) {
269 j
= find_cmd(argv
[d
]);
271 if (bdcms
[j
].argname
)
275 if (!strcmp(argv
[d
], "--getsz"))
277 if (!strcmp(argv
[d
], "--")) {
281 if (argv
[d
][0] != '-')
286 warnx(_("no device specified"));
287 errtryhelp(EXIT_FAILURE
);
290 for (k
= d
; k
< argc
; k
++) {
291 fd
= open(argv
[k
], O_RDONLY
, 0);
293 err(EXIT_FAILURE
, _("cannot open %s"), argv
[k
]);
294 do_commands(fd
, argv
, d
);
300 static void do_commands(int fd
, char **argv
, int d
)
304 unsigned int uarg
= 0;
305 unsigned short huarg
= 0;
308 unsigned long lu
= 0;
309 unsigned long long llu
= 0;
312 for (i
= 1; i
< d
; i
++) {
313 if (!strcmp(argv
[i
], "-v")) {
317 if (!strcmp(argv
[i
], "-q")) {
322 if (!strcmp(argv
[i
], "--getsz")) {
323 res
= blkdev_get_sectors(fd
, &llu
);
325 printf("%lld\n", llu
);
328 _("could not get device size"));
332 j
= find_cmd(argv
[i
]);
334 warnx(_("Unknown command: %s"), argv
[i
]);
335 errtryhelp(EXIT_FAILURE
);
338 switch (bdcms
[j
].argtype
) {
341 res
= ioctl(fd
, bdcms
[j
].ioc
, 0);
344 huarg
= bdcms
[j
].argval
;
345 res
= ioctl(fd
, bdcms
[j
].ioc
, &huarg
);
348 if (bdcms
[j
].argname
) {
350 warnx(_("%s requires an argument"),
352 errtryhelp(EXIT_FAILURE
);
354 iarg
= atoi(argv
[++i
]);
356 iarg
= bdcms
[j
].argval
;
358 res
= bdcms
[j
].flags
& FL_NOPTR
?
359 ioctl(fd
, bdcms
[j
].ioc
, iarg
) :
360 ioctl(fd
, bdcms
[j
].ioc
, &iarg
);
363 uarg
= bdcms
[j
].argval
;
364 res
= ioctl(fd
, bdcms
[j
].ioc
, &uarg
);
367 larg
= bdcms
[j
].argval
;
368 res
= ioctl(fd
, bdcms
[j
].ioc
, &larg
);
371 llarg
= bdcms
[j
].argval
;
372 res
= ioctl(fd
, bdcms
[j
].ioc
, &llarg
);
375 lu
= bdcms
[j
].argval
;
376 res
= ioctl(fd
, bdcms
[j
].ioc
, &lu
);
379 llu
= bdcms
[j
].argval
;
380 res
= ioctl(fd
, bdcms
[j
].ioc
, &llu
);
385 warn(_("ioctl error on %s"), bdcms
[j
].iocname
);
387 printf(_("%s failed.\n"), _(bdcms
[j
].help
));
391 if (bdcms
[j
].argtype
== ARG_NONE
||
392 (bdcms
[j
].flags
& FL_NORESULT
)) {
394 printf(_("%s succeeded.\n"), _(bdcms
[j
].help
));
399 printf("%s: ", _(bdcms
[j
].help
));
401 switch (bdcms
[j
].argtype
) {
403 printf("%hu\n", huarg
);
406 printf("%d\n", iarg
);
409 printf("%u\n", uarg
);
412 printf("%ld\n", larg
);
415 printf("%lld\n", llarg
);
421 printf("%llu\n", llu
);
427 static void report_all_devices(void)
431 char ptname
[200 + 1];
435 procpt
= fopen(_PATH_PROC_PARTITIONS
, "r");
437 err(EXIT_FAILURE
, _("cannot open %s"), _PATH_PROC_PARTITIONS
);
439 while (fgets(line
, sizeof(line
), procpt
)) {
440 if (sscanf(line
, " %d %d %d %200[^\n ]",
441 &ma
, &mi
, &sz
, ptname
) != 4)
444 sprintf(device
, "/dev/%s", ptname
);
445 report_device(device
, 1);
451 static void report_device(char *device
, int quiet
)
456 unsigned long long bytes
;
460 fd
= open(device
, O_RDONLY
| O_NONBLOCK
);
463 warn(_("cannot open %s"), device
);
469 if (fstat(fd
, &st
) == 0) {
473 pc
= ul_new_sysfs_path(st
.st_rdev
, NULL
, NULL
);
475 sysfs_blkdev_get_wholedisk(pc
, NULL
, 0, &disk
) == 0 &&
476 disk
!= st
.st_rdev
) {
478 if (ul_path_read_u64(pc
, &start
, "start") != 0)
480 _("%s: failed to read partition start from sysfs"),
485 if (ioctl(fd
, BLKROGET
, &ro
) == 0 &&
486 ioctl(fd
, BLKRAGET
, &ra
) == 0 &&
487 ioctl(fd
, BLKSSZGET
, &ssz
) == 0 &&
488 ioctl(fd
, BLKBSZGET
, &bsz
) == 0 &&
489 blkdev_get_size(fd
, &bytes
) == 0) {
490 printf("%s %5ld %5d %5d %10ju %15lld %s\n",
491 ro
? "ro" : "rw", ra
, ssz
, bsz
, start
, bytes
, device
);
494 warnx(_("ioctl error on %s"), device
);
500 static void report_header(void)
502 printf(_("RO RA SSZ BSZ StartSec Size Device\n"));