]> git.ipfire.org Git - thirdparty/util-linux.git/blob - disk-utils/blockdev.c
sfdisk: disambiguate units of --show-size
[thirdparty/util-linux.git] / disk-utils / blockdev.c
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>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <sys/ioctl.h>
12 #include <errno.h>
13
14 #include "c.h"
15 #include "nls.h"
16 #include "blkdev.h"
17 #include "pathnames.h"
18 #include "closestream.h"
19 #include "sysfs.h"
20
21 struct bdc {
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 */
36 enum {
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 */
42 enum {
43 ARG_NONE,
44 ARG_USHRT,
45 ARG_INT,
46 ARG_UINT,
47 ARG_LONG,
48 ARG_ULONG,
49 ARG_LLONG,
50 ARG_ULLONG
51 };
52
53 #define IOCTL_ENTRY( io ) .ioc = io, .iocname = # io
54
55 static const struct bdc bdcms[] =
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")
77 },{
78 IOCTL_ENTRY(BLKDISCARDZEROES),
79 .name = "--getdiscardzeroes",
80 .argtype = ARG_UINT,
81 .argval = -1,
82 .help = N_("get discard zeroes support status")
83 },{
84 IOCTL_ENTRY(BLKSSZGET),
85 .name = "--getss",
86 .argtype = ARG_INT,
87 .argval = -1,
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,
111 .argval = -1,
112 .help = N_("get alignment offset in bytes")
113 },{
114 IOCTL_ENTRY(BLKSECTGET),
115 .name = "--getmaxsect",
116 .argtype = ARG_USHRT,
117 .argval = -1,
118 .help = N_("get max sectors per request")
119 },{
120 IOCTL_ENTRY(BLKBSZGET),
121 .name = "--getbsz",
122 .argtype = ARG_INT,
123 .argval = -1,
124 .help = N_("get blocksize")
125 },{
126 IOCTL_ENTRY(BLKBSZSET),
127 .name = "--setbsz",
128 .argname = "<bytes>",
129 .argtype = ARG_INT,
130 .flags = FL_NORESULT,
131 .help = N_("set blocksize on file descriptor opening the block device")
132 },{
133 IOCTL_ENTRY(BLKGETSIZE),
134 .name = "--getsize",
135 .argtype = ARG_ULONG,
136 .argval = -1,
137 .help = N_("get 32-bit sector count (deprecated, use --getsz)")
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",
147 .argname = "<sectors>",
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",
160 .argname = "<sectors>",
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 }
179 };
180
181 static void __attribute__ ((__noreturn__)) usage(FILE * out)
182 {
183 size_t i;
184 fprintf(out, _("\nUsage:\n"
185 " %1$s -V\n"
186 " %1$s --report [devices]\n"
187 " %1$s [-v|-q] commands devices\n\n"
188 "Available commands:\n"), program_invocation_short_name);
189
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));
196 else
197 fprintf(out, " %-25s %s\n", bdcms[i].name,
198 _(bdcms[i].help));
199 }
200 fputc('\n', out);
201 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
202 }
203
204 static int find_cmd(char *s)
205 {
206 size_t j;
207
208 for (j = 0; j < ARRAY_SIZE(bdcms); j++)
209 if (!strcmp(s, bdcms[j].name))
210 return j;
211 return -1;
212 }
213
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);
218
219 int main(int argc, char **argv)
220 {
221 int fd, d, j, k;
222
223 setlocale(LC_ALL, "");
224 bindtextdomain(PACKAGE, LOCALEDIR);
225 textdomain(PACKAGE);
226 atexit(close_stdout);
227
228 if (argc < 2)
229 usage(stderr);
230
231 /* -V not together with commands */
232 if (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")) {
233 printf(UTIL_LINUX_VERSION);
234 return EXIT_SUCCESS;
235 }
236 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
237 usage(stdout);
238
239 /* --report not together with other commands */
240 if (!strcmp(argv[1], "--report")) {
241 report_header();
242 if (argc > 2) {
243 for (d = 2; d < argc; d++)
244 report_device(argv[d], 0);
245 } else {
246 report_all_devices();
247 }
248 return EXIT_SUCCESS;
249 }
250
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]);
255 if (j >= 0) {
256 if (bdcms[j].argname)
257 d++;
258 continue;
259 }
260 if (!strcmp(argv[d], "--getsz"))
261 continue;
262 if (!strcmp(argv[d], "--")) {
263 d++;
264 break;
265 }
266 if (argv[d][0] != '-')
267 break;
268 }
269
270 if (d >= argc)
271 usage(stderr);
272
273 for (k = d; k < argc; k++) {
274 fd = open(argv[k], O_RDONLY, 0);
275 if (fd < 0)
276 err(EXIT_FAILURE, _("cannot open %s"), argv[k]);
277 do_commands(fd, argv, d);
278 close(fd);
279 }
280 return EXIT_SUCCESS;
281 }
282
283 static void do_commands(int fd, char **argv, int d)
284 {
285 int res, i, j;
286 int iarg = 0;
287 unsigned int uarg = 0;
288 unsigned short huarg = 0;
289 long larg = 0;
290 long long llarg = 0;
291 unsigned long lu = 0;
292 unsigned long long llu = 0;
293 int verbose = 0;
294
295 for (i = 1; i < d; i++) {
296 if (!strcmp(argv[i], "-v")) {
297 verbose = 1;
298 continue;
299 }
300 if (!strcmp(argv[i], "-q")) {
301 verbose = 0;
302 continue;
303 }
304
305 if (!strcmp(argv[i], "--getsz")) {
306 res = blkdev_get_sectors(fd, &llu);
307 if (res == 0)
308 printf("%lld\n", llu);
309 else
310 errx(EXIT_FAILURE,
311 _("could not get device size"));
312 continue;
313 }
314
315 j = find_cmd(argv[i]);
316 if (j == -1) {
317 warnx(_("Unknown command: %s"), argv[i]);
318 usage(stderr);
319 }
320
321 switch (bdcms[j].argtype) {
322 default:
323 case ARG_NONE:
324 res = ioctl(fd, bdcms[j].ioc, 0);
325 break;
326 case ARG_USHRT:
327 huarg = bdcms[j].argval;
328 res = ioctl(fd, bdcms[j].ioc, &huarg);
329 break;
330 case ARG_INT:
331 if (bdcms[j].argname) {
332 if (i == d - 1) {
333 warnx(_("%s requires an argument"),
334 bdcms[j].name);
335 usage(stderr);
336 }
337 iarg = atoi(argv[++i]);
338 } else
339 iarg = bdcms[j].argval;
340
341 res = bdcms[j].flags & FL_NOPTR ?
342 ioctl(fd, bdcms[j].ioc, iarg) :
343 ioctl(fd, bdcms[j].ioc, &iarg);
344 break;
345 case ARG_UINT:
346 uarg = bdcms[j].argval;
347 res = ioctl(fd, bdcms[j].ioc, &uarg);
348 break;
349 case ARG_LONG:
350 larg = bdcms[j].argval;
351 res = ioctl(fd, bdcms[j].ioc, &larg);
352 break;
353 case ARG_LLONG:
354 llarg = bdcms[j].argval;
355 res = ioctl(fd, bdcms[j].ioc, &llarg);
356 break;
357 case ARG_ULONG:
358 lu = bdcms[j].argval;
359 res = ioctl(fd, bdcms[j].ioc, &lu);
360 break;
361 case ARG_ULLONG:
362 llu = bdcms[j].argval;
363 res = ioctl(fd, bdcms[j].ioc, &llu);
364 break;
365 }
366
367 if (res == -1) {
368 warn(_("ioctl error on %s"), bdcms[j].iocname);
369 if (verbose)
370 printf(_("%s failed.\n"), _(bdcms[j].help));
371 exit(EXIT_FAILURE);
372 }
373
374 if (bdcms[j].argtype == ARG_NONE ||
375 (bdcms[j].flags & FL_NORESULT)) {
376 if (verbose)
377 printf(_("%s succeeded.\n"), _(bdcms[j].help));
378 continue;
379 }
380
381 if (verbose)
382 printf("%s: ", _(bdcms[j].help));
383
384 switch (bdcms[j].argtype) {
385 case ARG_USHRT:
386 printf("%hu\n", huarg);
387 break;
388 case ARG_INT:
389 printf("%d\n", iarg);
390 break;
391 case ARG_UINT:
392 printf("%u\n", uarg);
393 break;
394 case ARG_LONG:
395 printf("%ld\n", larg);
396 break;
397 case ARG_LLONG:
398 printf("%lld\n", llarg);
399 break;
400 case ARG_ULONG:
401 printf("%lu\n", lu);
402 break;
403 case ARG_ULLONG:
404 printf("%llu\n", llu);
405 break;
406 }
407 }
408 }
409
410 static void report_all_devices(void)
411 {
412 FILE *procpt;
413 char line[200];
414 char ptname[200 + 1];
415 char device[210];
416 int ma, mi, sz;
417
418 procpt = fopen(_PATH_PROC_PARTITIONS, "r");
419 if (!procpt)
420 err(EXIT_FAILURE, _("cannot open %s"), _PATH_PROC_PARTITIONS);
421
422 while (fgets(line, sizeof(line), procpt)) {
423 if (sscanf(line, " %d %d %d %200[^\n ]",
424 &ma, &mi, &sz, ptname) != 4)
425 continue;
426
427 sprintf(device, "/dev/%s", ptname);
428 report_device(device, 1);
429 }
430
431 fclose(procpt);
432 }
433
434 static void report_device(char *device, int quiet)
435 {
436 int fd;
437 int ro, ssz, bsz;
438 long ra;
439 unsigned long long bytes;
440 uint64_t start = 0;
441 struct stat st;
442
443 fd = open(device, O_RDONLY | O_NONBLOCK);
444 if (fd < 0) {
445 if (!quiet)
446 warn(_("cannot open %s"), device);
447 return;
448 }
449
450 ro = ssz = bsz = 0;
451 ra = 0;
452 if (fstat(fd, &st) == 0 && !sysfs_devno_is_wholedisk(st.st_rdev)) {
453 struct sysfs_cxt cxt;
454
455 if (sysfs_init(&cxt, st.st_rdev, NULL))
456 err(EXIT_FAILURE,
457 _("%s: failed to initialize sysfs handler"),
458 device);
459 if (sysfs_read_u64(&cxt, "start", &start))
460 err(EXIT_FAILURE,
461 _("%s: failed to read partition start from sysfs"),
462 device);
463 sysfs_deinit(&cxt);
464 }
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);
472 } else {
473 if (!quiet)
474 warnx(_("ioctl error on %s"), device);
475 }
476
477 close(fd);
478 }
479
480 static void report_header(void)
481 {
482 printf(_("RO RA SSZ BSZ StartSec Size Device\n"));
483 }