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(FILE * out
)
184 fprintf(out
, _("\nUsage:\n"
186 " %1$s --report [devices]\n"
187 " %1$s [-v|-q] commands devices\n\n"
188 "Available commands:\n"), program_invocation_short_name
);
190 fprintf(out
, _(" %-25s get size in 512-byte sectors\n"), "--getsz");
191 for (i
= 0; i
< ARRAY_SIZE(bdcms
); i
++) {
192 if (bdcms
[i
].argname
)
193 fprintf(out
, " %s %-*s %s\n", bdcms
[i
].name
,
194 (int)(24 - strlen(bdcms
[i
].name
)),
195 bdcms
[i
].argname
, _(bdcms
[i
].help
));
197 fprintf(out
, " %-25s %s\n", bdcms
[i
].name
,
201 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
204 static int find_cmd(char *s
)
208 for (j
= 0; j
< ARRAY_SIZE(bdcms
); j
++)
209 if (!strcmp(s
, bdcms
[j
].name
))
214 static void do_commands(int fd
, char **argv
, int d
);
215 static void report_header(void);
216 static void report_device(char *device
, int quiet
);
217 static void report_all_devices(void);
219 int main(int argc
, char **argv
)
223 setlocale(LC_ALL
, "");
224 bindtextdomain(PACKAGE
, LOCALEDIR
);
226 atexit(close_stdout
);
231 /* -V not together with commands */
232 if (!strcmp(argv
[1], "-V") || !strcmp(argv
[1], "--version")) {
233 printf(UTIL_LINUX_VERSION
);
236 if (!strcmp(argv
[1], "-h") || !strcmp(argv
[1], "--help"))
239 /* --report not together with other commands */
240 if (!strcmp(argv
[1], "--report")) {
243 for (d
= 2; d
< argc
; d
++)
244 report_device(argv
[d
], 0);
246 report_all_devices();
251 /* do each of the commands on each of the devices */
252 /* devices start after last command */
253 for (d
= 1; d
< argc
; d
++) {
254 j
= find_cmd(argv
[d
]);
256 if (bdcms
[j
].argname
)
260 if (!strcmp(argv
[d
], "--getsz"))
262 if (!strcmp(argv
[d
], "--")) {
266 if (argv
[d
][0] != '-')
273 for (k
= d
; k
< argc
; k
++) {
274 fd
= open(argv
[k
], O_RDONLY
, 0);
276 err(EXIT_FAILURE
, _("cannot open %s"), argv
[k
]);
277 do_commands(fd
, argv
, d
);
283 static void do_commands(int fd
, char **argv
, int d
)
287 unsigned int uarg
= 0;
288 unsigned short huarg
= 0;
291 unsigned long lu
= 0;
292 unsigned long long llu
= 0;
295 for (i
= 1; i
< d
; i
++) {
296 if (!strcmp(argv
[i
], "-v")) {
300 if (!strcmp(argv
[i
], "-q")) {
305 if (!strcmp(argv
[i
], "--getsz")) {
306 res
= blkdev_get_sectors(fd
, &llu
);
308 printf("%lld\n", llu
);
311 _("could not get device size"));
315 j
= find_cmd(argv
[i
]);
317 warnx(_("Unknown command: %s"), argv
[i
]);
321 switch (bdcms
[j
].argtype
) {
324 res
= ioctl(fd
, bdcms
[j
].ioc
, 0);
327 huarg
= bdcms
[j
].argval
;
328 res
= ioctl(fd
, bdcms
[j
].ioc
, &huarg
);
331 if (bdcms
[j
].argname
) {
333 warnx(_("%s requires an argument"),
337 iarg
= atoi(argv
[++i
]);
339 iarg
= bdcms
[j
].argval
;
341 res
= bdcms
[j
].flags
& FL_NOPTR
?
342 ioctl(fd
, bdcms
[j
].ioc
, iarg
) :
343 ioctl(fd
, bdcms
[j
].ioc
, &iarg
);
346 uarg
= bdcms
[j
].argval
;
347 res
= ioctl(fd
, bdcms
[j
].ioc
, &uarg
);
350 larg
= bdcms
[j
].argval
;
351 res
= ioctl(fd
, bdcms
[j
].ioc
, &larg
);
354 llarg
= bdcms
[j
].argval
;
355 res
= ioctl(fd
, bdcms
[j
].ioc
, &llarg
);
358 lu
= bdcms
[j
].argval
;
359 res
= ioctl(fd
, bdcms
[j
].ioc
, &lu
);
362 llu
= bdcms
[j
].argval
;
363 res
= ioctl(fd
, bdcms
[j
].ioc
, &llu
);
368 warn(_("ioctl error on %s"), bdcms
[j
].iocname
);
370 printf(_("%s failed.\n"), _(bdcms
[j
].help
));
374 if (bdcms
[j
].argtype
== ARG_NONE
||
375 (bdcms
[j
].flags
& FL_NORESULT
)) {
377 printf(_("%s succeeded.\n"), _(bdcms
[j
].help
));
382 printf("%s: ", _(bdcms
[j
].help
));
384 switch (bdcms
[j
].argtype
) {
386 printf("%hu\n", huarg
);
389 printf("%d\n", iarg
);
392 printf("%u\n", uarg
);
395 printf("%ld\n", larg
);
398 printf("%lld\n", llarg
);
404 printf("%llu\n", llu
);
410 static void report_all_devices(void)
414 char ptname
[200 + 1];
418 procpt
= fopen(_PATH_PROC_PARTITIONS
, "r");
420 err(EXIT_FAILURE
, _("cannot open %s"), _PATH_PROC_PARTITIONS
);
422 while (fgets(line
, sizeof(line
), procpt
)) {
423 if (sscanf(line
, " %d %d %d %200[^\n ]",
424 &ma
, &mi
, &sz
, ptname
) != 4)
427 sprintf(device
, "/dev/%s", ptname
);
428 report_device(device
, 1);
434 static void report_device(char *device
, int quiet
)
439 unsigned long long bytes
;
443 fd
= open(device
, O_RDONLY
| O_NONBLOCK
);
446 warn(_("cannot open %s"), device
);
452 if (fstat(fd
, &st
) == 0 && !sysfs_devno_is_wholedisk(st
.st_rdev
)) {
453 struct sysfs_cxt cxt
;
455 if (sysfs_init(&cxt
, st
.st_rdev
, NULL
))
457 _("%s: failed to initialize sysfs handler"),
459 if (sysfs_read_u64(&cxt
, "start", &start
))
461 _("%s: failed to read partition start from sysfs"),
465 if (ioctl(fd
, BLKROGET
, &ro
) == 0 &&
466 ioctl(fd
, BLKRAGET
, &ra
) == 0 &&
467 ioctl(fd
, BLKSSZGET
, &ssz
) == 0 &&
468 ioctl(fd
, BLKBSZGET
, &bsz
) == 0 &&
469 blkdev_get_size(fd
, &bytes
) == 0) {
470 printf("%s %5ld %5d %5d %10ju %15lld %s\n",
471 ro
? "ro" : "rw", ra
, ssz
, bsz
, start
, bytes
, device
);
474 warnx(_("ioctl error on %s"), device
);
480 static void report_header(void)
482 printf(_("RO RA SSZ BSZ StartSec Size Device\n"));