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