]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/blockdev.c
misc: consolidate version printing and close_stdout()
[thirdparty/util-linux.git] / disk-utils / blockdev.c
CommitLineData
eb63b9b8
KZ
1/*
2 * blockdev.c --- Do various simple block device ioctls from the command line
3 * aeb, 991028
4 */
5
6#include <stdio.h>
7#include <fcntl.h>
eb63b9b8
KZ
8#include <stdlib.h>
9#include <string.h>
10#include <unistd.h>
11#include <sys/ioctl.h>
3281d426 12#include <errno.h>
eb63b9b8 13
515422fd 14#include "c.h"
eb63b9b8 15#include "nls.h"
bc8b6383 16#include "blkdev.h"
14c76d8b 17#include "pathnames.h"
45ca68ec 18#include "closestream.h"
569d1dac 19#include "sysfs.h"
612721db 20
eb63b9b8 21struct bdc {
c3f62be7
KZ
22 long ioc; /* ioctl code */
23 const char *iocname; /* ioctl name (e.g. BLKROSET) */
24 long argval; /* default argument */
25
26 const char *name; /* --setfoo */
27 const char *argname; /* argument name or NULL */
28
29 const char *help;
30
31 int argtype;
32 int flags;
33};
34
35/* command flags */
36enum {
37 FL_NOPTR = (1 << 1), /* does not assume pointer (ARG_INT only)*/
38 FL_NORESULT = (1 << 2) /* does not return any data */
39};
40
41/* ioctl argument types */
42enum {
43 ARG_NONE,
726fa24e 44 ARG_USHRT,
c3f62be7 45 ARG_INT,
726fa24e 46 ARG_UINT,
c3f62be7
KZ
47 ARG_LONG,
48 ARG_ULONG,
49 ARG_LLONG,
50 ARG_ULLONG
51};
52
53#define IOCTL_ENTRY( io ) .ioc = io, .iocname = # io
54
00239f33 55static const struct bdc bdcms[] =
c3f62be7
KZ
56{
57 {
58 IOCTL_ENTRY(BLKROSET),
59 .name = "--setro",
60 .argtype = ARG_INT,
61 .argval = 1,
62 .flags = FL_NORESULT,
63 .help = N_("set read-only")
64 },{
65 IOCTL_ENTRY(BLKROSET),
66 .name = "--setrw",
67 .argtype = ARG_INT,
68 .argval = 0,
69 .flags = FL_NORESULT,
70 .help = N_("set read-write")
71 },{
72 IOCTL_ENTRY(BLKROGET),
73 .name = "--getro",
74 .argtype = ARG_INT,
75 .argval = -1,
76 .help = N_("get read-only")
1519ab5f
KZ
77 },{
78 IOCTL_ENTRY(BLKDISCARDZEROES),
79 .name = "--getdiscardzeroes",
80 .argtype = ARG_UINT,
81 .argval = -1,
82 .help = N_("get discard zeroes support status")
c3f62be7
KZ
83 },{
84 IOCTL_ENTRY(BLKSSZGET),
85 .name = "--getss",
86 .argtype = ARG_INT,
87 .argval = -1,
d965d63f
KZ
88 .help = N_("get logical block (sector) size")
89 },{
90 IOCTL_ENTRY(BLKPBSZGET),
91 .name = "--getpbsz",
92 .argtype = ARG_UINT,
93 .argval = -1,
94 .help = N_("get physical block (sector) size")
95 },{
96 IOCTL_ENTRY(BLKIOMIN),
97 .name = "--getiomin",
98 .argtype = ARG_UINT,
99 .argval = -1,
100 .help = N_("get minimum I/O size")
101 },{
102 IOCTL_ENTRY(BLKIOOPT),
103 .name = "--getioopt",
104 .argtype = ARG_UINT,
105 .argval = -1,
106 .help = N_("get optimal I/O size")
107 },{
108 IOCTL_ENTRY(BLKALIGNOFF),
109 .name = "--getalignoff",
110 .argtype = ARG_INT,
ed98508a 111 .argval = -1,
455fdf4a 112 .help = N_("get alignment offset in bytes")
d965d63f
KZ
113 },{
114 IOCTL_ENTRY(BLKSECTGET),
115 .name = "--getmaxsect",
116 .argtype = ARG_USHRT,
117 .argval = -1,
118 .help = N_("get max sectors per request")
c3f62be7
KZ
119 },{
120 IOCTL_ENTRY(BLKBSZGET),
121 .name = "--getbsz",
122 .argtype = ARG_INT,
123 .argval = -1,
124 .help = N_("get blocksize")
39d2e706
KZ
125 },{
126 IOCTL_ENTRY(BLKBSZSET),
127 .name = "--setbsz",
128 .argname = "<bytes>",
129 .argtype = ARG_INT,
130 .flags = FL_NORESULT,
7ab32ae6 131 .help = N_("set blocksize on file descriptor opening the block device")
c3f62be7
KZ
132 },{
133 IOCTL_ENTRY(BLKGETSIZE),
134 .name = "--getsize",
135 .argtype = ARG_ULONG,
136 .argval = -1,
455fdf4a 137 .help = N_("get 32-bit sector count (deprecated, use --getsz)")
c3f62be7
KZ
138 },{
139 IOCTL_ENTRY(BLKGETSIZE64),
140 .name = "--getsize64",
141 .argtype = ARG_ULLONG,
142 .argval = -1,
143 .help = N_("get size in bytes")
144 },{
145 IOCTL_ENTRY(BLKRASET),
146 .name = "--setra",
455fdf4a 147 .argname = "<sectors>",
c3f62be7
KZ
148 .argtype = ARG_INT,
149 .flags = FL_NOPTR | FL_NORESULT,
150 .help = N_("set readahead")
151 },{
152 IOCTL_ENTRY(BLKRAGET),
153 .name = "--getra",
154 .argtype = ARG_LONG,
155 .argval = -1,
156 .help = N_("get readahead")
157 },{
158 IOCTL_ENTRY(BLKFRASET),
159 .name = "--setfra",
455fdf4a 160 .argname = "<sectors>",
c3f62be7
KZ
161 .argtype = ARG_INT,
162 .flags = FL_NOPTR | FL_NORESULT,
163 .help = N_("set filesystem readahead")
164 },{
165 IOCTL_ENTRY(BLKFRAGET),
166 .name = "--getfra",
167 .argtype = ARG_LONG,
168 .argval = -1,
169 .help = N_("get filesystem readahead")
170 },{
171 IOCTL_ENTRY(BLKFLSBUF),
172 .name = "--flushbufs",
173 .help = N_("flush buffers")
174 },{
175 IOCTL_ENTRY(BLKRRPART),
176 .name = "--rereadpt",
177 .help = N_("reread partition table")
178 }
eb63b9b8
KZ
179};
180
9325dbfd 181static void __attribute__((__noreturn__)) usage(void)
bded204c 182{
75737ad6 183 size_t i;
9325dbfd 184
a861538c
RM
185 fputs(USAGE_HEADER, stdout);
186 printf(_(
187 " %1$s [-v|-q] commands devices\n"
188 " %1$s --report [devices]\n"
189 " %1$s -h|-V\n"
190 ), program_invocation_short_name);
a424171c 191
a861538c
RM
192 fputs(USAGE_SEPARATOR, stdout);
193 puts( _("Call block device ioctls from the command line."));
194
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);
f45f3ec3 200 printf(USAGE_HELP_OPTIONS(16));
a861538c
RM
201
202 fputs(USAGE_SEPARATOR, stdout);
203 puts( _("Available commands:"));
204 printf(_(" %-25s get size in 512-byte sectors\n"), "--getsz");
515422fd 205 for (i = 0; i < ARRAY_SIZE(bdcms); i++) {
eb63b9b8 206 if (bdcms[i].argname)
a861538c 207 printf(" %s %-*s %s\n", bdcms[i].name,
bded204c
SK
208 (int)(24 - strlen(bdcms[i].name)),
209 bdcms[i].argname, _(bdcms[i].help));
a424171c 210 else
a861538c 211 printf(" %-25s %s\n", bdcms[i].name,
bded204c 212 _(bdcms[i].help));
eb63b9b8 213 }
9325dbfd 214
43c960c8 215 printf(USAGE_MAN_TAIL("blockdev(8)"));
9325dbfd 216 exit(EXIT_SUCCESS);
eb63b9b8
KZ
217}
218
baaa4479
SK
219static int find_cmd(char *s)
220{
75737ad6 221 size_t j;
eb63b9b8 222
515422fd 223 for (j = 0; j < ARRAY_SIZE(bdcms); j++)
eb63b9b8
KZ
224 if (!strcmp(s, bdcms[j].name))
225 return j;
226 return -1;
227}
228
f61a097b
WG
229static void do_commands(int fd, char **argv, int d);
230static void report_header(void);
231static void report_device(char *device, int quiet);
232static void report_all_devices(void);
eb63b9b8 233
baaa4479
SK
234int main(int argc, char **argv)
235{
eb63b9b8 236 int fd, d, j, k;
eb63b9b8 237
eb63b9b8
KZ
238 setlocale(LC_ALL, "");
239 bindtextdomain(PACKAGE, LOCALEDIR);
240 textdomain(PACKAGE);
2c308875 241 close_stdout_atexit();
eb63b9b8 242
9325dbfd
RM
243 if (argc < 2) {
244 warnx(_("not enough arguments"));
245 errtryhelp(EXIT_FAILURE);
246 }
eb63b9b8
KZ
247
248 /* -V not together with commands */
2c308875
KZ
249 if (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version"))
250 print_version(EXIT_SUCCESS);
bded204c 251 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
9325dbfd 252 usage();
eb63b9b8 253
612721db
KZ
254 /* --report not together with other commands */
255 if (!strcmp(argv[1], "--report")) {
256 report_header();
257 if (argc > 2) {
258 for (d = 2; d < argc; d++)
259 report_device(argv[d], 0);
260 } else {
261 report_all_devices();
262 }
6b515d0b 263 return EXIT_SUCCESS;
612721db
KZ
264 }
265
eb63b9b8
KZ
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]);
270 if (j >= 0) {
c3f62be7 271 if (bdcms[j].argname)
eb63b9b8
KZ
272 d++;
273 continue;
274 }
c129767e
KZ
275 if (!strcmp(argv[d], "--getsz"))
276 continue;
eb63b9b8
KZ
277 if (!strcmp(argv[d], "--")) {
278 d++;
279 break;
280 }
281 if (argv[d][0] != '-')
282 break;
283 }
284
9325dbfd
RM
285 if (d >= argc) {
286 warnx(_("no device specified"));
287 errtryhelp(EXIT_FAILURE);
288 }
eb63b9b8
KZ
289
290 for (k = d; k < argc; k++) {
291 fd = open(argv[k], O_RDONLY, 0);
6b515d0b
SK
292 if (fd < 0)
293 err(EXIT_FAILURE, _("cannot open %s"), argv[k]);
eb63b9b8 294 do_commands(fd, argv, d);
e8f26419 295 close(fd);
eb63b9b8 296 }
6b515d0b 297 return EXIT_SUCCESS;
eb63b9b8
KZ
298}
299
f61a097b 300static void do_commands(int fd, char **argv, int d)
baaa4479 301{
eb63b9b8 302 int res, i, j;
15705de0
KZ
303 int iarg = 0;
304 unsigned int uarg = 0;
305 unsigned short huarg = 0;
306 long larg = 0;
307 long long llarg = 0;
308 unsigned long lu = 0;
309 unsigned long long llu = 0;
eb63b9b8
KZ
310 int verbose = 0;
311
312 for (i = 1; i < d; i++) {
313 if (!strcmp(argv[i], "-v")) {
314 verbose = 1;
315 continue;
baaa4479 316 }
eb63b9b8
KZ
317 if (!strcmp(argv[i], "-q")) {
318 verbose = 0;
319 continue;
320 }
321
c129767e 322 if (!strcmp(argv[i], "--getsz")) {
bc8b6383 323 res = blkdev_get_sectors(fd, &llu);
c129767e 324 if (res == 0)
bc8b6383 325 printf("%lld\n", llu);
c129767e 326 else
baaa4479
SK
327 errx(EXIT_FAILURE,
328 _("could not get device size"));
c129767e
KZ
329 continue;
330 }
331
eb63b9b8
KZ
332 j = find_cmd(argv[i]);
333 if (j == -1) {
cc4d8d72 334 warnx(_("Unknown command: %s"), argv[i]);
9325dbfd 335 errtryhelp(EXIT_FAILURE);
eb63b9b8
KZ
336 }
337
baaa4479 338 switch (bdcms[j].argtype) {
eb63b9b8 339 default:
c3f62be7 340 case ARG_NONE:
eb63b9b8
KZ
341 res = ioctl(fd, bdcms[j].ioc, 0);
342 break;
726fa24e
KZ
343 case ARG_USHRT:
344 huarg = bdcms[j].argval;
345 res = ioctl(fd, bdcms[j].ioc, &huarg);
346 break;
c3f62be7
KZ
347 case ARG_INT:
348 if (bdcms[j].argname) {
baaa4479 349 if (i == d - 1) {
cc4d8d72 350 warnx(_("%s requires an argument"),
baaa4479 351 bdcms[j].name);
9325dbfd 352 errtryhelp(EXIT_FAILURE);
c3f62be7
KZ
353 }
354 iarg = atoi(argv[++i]);
355 } else
356 iarg = bdcms[j].argval;
357
358 res = bdcms[j].flags & FL_NOPTR ?
baaa4479
SK
359 ioctl(fd, bdcms[j].ioc, iarg) :
360 ioctl(fd, bdcms[j].ioc, &iarg);
eb63b9b8 361 break;
726fa24e
KZ
362 case ARG_UINT:
363 uarg = bdcms[j].argval;
364 res = ioctl(fd, bdcms[j].ioc, &uarg);
365 break;
c3f62be7 366 case ARG_LONG:
eb63b9b8
KZ
367 larg = bdcms[j].argval;
368 res = ioctl(fd, bdcms[j].ioc, &larg);
369 break;
c3f62be7 370 case ARG_LLONG:
c129767e
KZ
371 llarg = bdcms[j].argval;
372 res = ioctl(fd, bdcms[j].ioc, &llarg);
373 break;
c3f62be7 374 case ARG_ULONG:
1dea05a8
KZ
375 lu = bdcms[j].argval;
376 res = ioctl(fd, bdcms[j].ioc, &lu);
377 break;
c3f62be7 378 case ARG_ULLONG:
1dea05a8
KZ
379 llu = bdcms[j].argval;
380 res = ioctl(fd, bdcms[j].ioc, &llu);
381 break;
eb63b9b8 382 }
c3f62be7 383
eb63b9b8 384 if (res == -1) {
338a6bc5 385 warn(_("ioctl error on %s"), bdcms[j].iocname);
eb63b9b8 386 if (verbose)
65b27d36 387 printf(_("%s failed.\n"), _(bdcms[j].help));
6b515d0b 388 exit(EXIT_FAILURE);
eb63b9b8 389 }
c3f62be7
KZ
390
391 if (bdcms[j].argtype == ARG_NONE ||
392 (bdcms[j].flags & FL_NORESULT)) {
eb63b9b8 393 if (verbose)
c3f62be7
KZ
394 printf(_("%s succeeded.\n"), _(bdcms[j].help));
395 continue;
396 }
397
398 if (verbose)
399 printf("%s: ", _(bdcms[j].help));
400
baaa4479 401 switch (bdcms[j].argtype) {
726fa24e
KZ
402 case ARG_USHRT:
403 printf("%hu\n", huarg);
404 break;
c3f62be7
KZ
405 case ARG_INT:
406 printf("%d\n", iarg);
eb63b9b8 407 break;
726fa24e
KZ
408 case ARG_UINT:
409 printf("%u\n", uarg);
410 break;
c3f62be7
KZ
411 case ARG_LONG:
412 printf("%ld\n", larg);
c129767e 413 break;
c3f62be7
KZ
414 case ARG_LLONG:
415 printf("%lld\n", llarg);
1dea05a8 416 break;
c3f62be7
KZ
417 case ARG_ULONG:
418 printf("%lu\n", lu);
1dea05a8 419 break;
c3f62be7
KZ
420 case ARG_ULLONG:
421 printf("%llu\n", llu);
eb63b9b8
KZ
422 break;
423 }
424 }
425}
612721db 426
f61a097b 427static void report_all_devices(void)
baaa4479 428{
612721db
KZ
429 FILE *procpt;
430 char line[200];
657d9adb 431 char ptname[200 + 1];
612721db
KZ
432 char device[210];
433 int ma, mi, sz;
434
14c76d8b 435 procpt = fopen(_PATH_PROC_PARTITIONS, "r");
cc4d8d72 436 if (!procpt)
14c76d8b 437 err(EXIT_FAILURE, _("cannot open %s"), _PATH_PROC_PARTITIONS);
612721db
KZ
438
439 while (fgets(line, sizeof(line), procpt)) {
baaa4479
SK
440 if (sscanf(line, " %d %d %d %200[^\n ]",
441 &ma, &mi, &sz, ptname) != 4)
612721db
KZ
442 continue;
443
444 sprintf(device, "/dev/%s", ptname);
445 report_device(device, 1);
446 }
122db55d 447
448 fclose(procpt);
612721db
KZ
449}
450
f61a097b 451static void report_device(char *device, int quiet)
baaa4479 452{
612721db
KZ
453 int fd;
454 int ro, ssz, bsz;
bc8b6383
KZ
455 long ra;
456 unsigned long long bytes;
569d1dac 457 uint64_t start = 0;
569d1dac 458 struct stat st;
612721db
KZ
459
460 fd = open(device, O_RDONLY | O_NONBLOCK);
461 if (fd < 0) {
462 if (!quiet)
6b515d0b 463 warn(_("cannot open %s"), device);
612721db
KZ
464 return;
465 }
466
467 ro = ssz = bsz = 0;
569d1dac 468 ra = 0;
345ddd28
KZ
469 if (fstat(fd, &st) == 0) {
470 dev_t disk;
471 struct path_cxt *pc;
472
473 pc = ul_new_sysfs_path(st.st_rdev, NULL, NULL);
474 if (pc &&
475 sysfs_blkdev_get_wholedisk(pc, NULL, 0, &disk) == 0 &&
476 disk != st.st_rdev) {
477
478 if (ul_path_read_u64(pc, &start, "start") != 0)
479 err(EXIT_FAILURE,
480 _("%s: failed to read partition start from sysfs"),
481 device);
482 }
483 ul_unref_path(pc);
569d1dac 484 }
baaa4479
SK
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 &&
baaa4479 489 blkdev_get_size(fd, &bytes) == 0) {
569d1dac
PS
490 printf("%s %5ld %5d %5d %10ju %15lld %s\n",
491 ro ? "ro" : "rw", ra, ssz, bsz, start, bytes, device);
612721db
KZ
492 } else {
493 if (!quiet)
cc4d8d72 494 warnx(_("ioctl error on %s"), device);
612721db 495 }
122db55d 496
497 close(fd);
612721db
KZ
498}
499
16bd8025 500static void report_header(void)
baaa4479 501{
bc8b6383 502 printf(_("RO RA SSZ BSZ StartSec Size Device\n"));
612721db 503}