]> git.ipfire.org Git - thirdparty/util-linux.git/blob - disk-utils/partx.c
Merge branch 'shell-completion' of git://github.com/kerolasa/lelux-utiliteetit
[thirdparty/util-linux.git] / disk-utils / partx.c
1 /*
2 * partx: tell the kernel about your disk's partitions
3 * [This is not an fdisk - adding and removing partitions
4 * is not a change of the disk, but just telling the kernel
5 * about presence and numbering of on-disk partitions.]
6 *
7 * aeb, 2000-03-21 -- sah is 42 now
8 *
9 * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
10 * Rewritten to use libblkid for util-linux
11 * based on ideas from Karel Zak <kzak@redhat.com>
12 */
13
14 #include <stdio.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <ctype.h>
18 #include <getopt.h>
19 #include <unistd.h>
20 #include <assert.h>
21 #include <dirent.h>
22
23 #include <blkid.h>
24
25 #include "c.h"
26 #include "pathnames.h"
27 #include "nls.h"
28 #include "tt.h"
29 #include "blkdev.h"
30 #include "strutils.h"
31 #include "xalloc.h"
32 #include "partx.h"
33 #include "sysfs.h"
34 #include "loopdev.h"
35 #include "at.h"
36 #include "closestream.h"
37 #include "optutils.h"
38
39 /* this is the default upper limit, could be modified by --nr */
40 #define SLICES_MAX 256
41
42 /* all the columns (-o option) */
43 enum {
44 COL_PARTNO,
45 COL_START,
46 COL_END,
47 COL_SECTORS,
48 COL_SIZE,
49 COL_NAME,
50 COL_UUID,
51 COL_TYPE,
52 COL_FLAGS,
53 COL_SCHEME,
54 };
55
56 #define ACT_ERROR "--{add,delete,show,list,raw,pairs}"
57 enum {
58 ACT_NONE,
59 ACT_LIST,
60 ACT_SHOW,
61 ACT_ADD,
62 ACT_UPD,
63 ACT_DELETE
64 };
65
66 enum {
67 FL_BYTES = (1 << 1)
68 };
69
70 /* column names */
71 struct colinfo {
72 const char *name; /* header */
73 double whint; /* width hint (N < 1 is in percent of termwidth) */
74 int flags; /* TT_FL_* */
75 const char *help;
76 };
77
78 /* columns descriptions */
79 struct colinfo infos[] = {
80 [COL_PARTNO] = { "NR", 0.25, TT_FL_RIGHT, N_("partition number") },
81 [COL_START] = { "START", 0.30, TT_FL_RIGHT, N_("start of the partition in sectors") },
82 [COL_END] = { "END", 0.30, TT_FL_RIGHT, N_("end of the partition in sectors") },
83 [COL_SECTORS] = { "SECTORS", 0.30, TT_FL_RIGHT, N_("number of sectors") },
84 [COL_SIZE] = { "SIZE", 0.30, TT_FL_RIGHT, N_("human readable size") },
85 [COL_NAME] = { "NAME", 0.30, TT_FL_TRUNC, N_("partition name") },
86 [COL_UUID] = { "UUID", 36, 0, N_("partition UUID")},
87 [COL_SCHEME] = { "SCHEME", 0.1, TT_FL_TRUNC, N_("partition table type (dos, gpt, ...)")},
88 [COL_FLAGS] = { "FLAGS", 0.1, TT_FL_TRUNC, N_("partition flags")},
89 [COL_TYPE] = { "TYPE", 1, TT_FL_RIGHT, N_("partition type hex or uuid")},
90 };
91
92 #define NCOLS ARRAY_SIZE(infos)
93
94 /* array with IDs of enabled columns */
95 static int columns[NCOLS], ncolumns;
96
97 static int verbose;
98 static int partx_flags;
99 static struct loopdev_cxt lc;
100 static int loopdev;
101
102 static void assoc_loopdev(const char *fname)
103 {
104 int rc;
105
106 if (loopcxt_init(&lc, 0))
107 err(EXIT_FAILURE, _("failed to initialize loopcxt"));
108
109 rc = loopcxt_find_unused(&lc);
110 if (rc)
111 err(EXIT_FAILURE, _("%s: failed to find unused loop device"),
112 fname);
113
114 if (verbose)
115 printf(_("Trying to use '%s' for the loop device\n"),
116 loopcxt_get_device(&lc));
117
118 if (loopcxt_set_backing_file(&lc, fname))
119 err(EXIT_FAILURE, _("%s: failed to set backing file"), fname);
120
121 rc = loopcxt_setup_device(&lc);
122
123 if (rc == -EBUSY)
124 err(EXIT_FAILURE, _("%s: failed to setup loop device"), fname);
125
126 loopdev = 1;
127 }
128
129 static inline int get_column_id(int num)
130 {
131 assert(ARRAY_SIZE(columns) == NCOLS);
132 assert(num < ncolumns);
133 assert(columns[num] < (int) NCOLS);
134 return columns[num];
135 }
136
137 static inline struct colinfo *get_column_info(int num)
138 {
139 return &infos[ get_column_id(num) ];
140 }
141
142 static int column_name_to_id(const char *name, size_t namesz)
143 {
144 size_t i;
145
146 assert(name);
147
148 for (i = 0; i < NCOLS; i++) {
149 const char *cn = infos[i].name;
150
151 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
152 return i;
153 }
154 warnx(_("unknown column: %s"), name);
155 return -1;
156 }
157
158 /*
159 * Given a partition return the corresponding partition number.
160 *
161 * Note that this function tries to use sysfs, otherwise it assumes that the
162 * last characters are always numeric (sda1, sdc20, etc).
163 */
164 static int get_partno_from_device(char *partition, dev_t devno)
165 {
166 int partno = 0;
167 size_t sz;
168 char *p, *end = NULL;
169
170 assert(partition);
171
172 if (devno) {
173 struct sysfs_cxt cxt;
174 int rc;
175
176 if (sysfs_init(&cxt, devno, NULL))
177 goto err;
178
179 rc = sysfs_read_int(&cxt, "partition", &partno);
180 sysfs_deinit(&cxt);
181
182 if (rc == 0)
183 return partno;
184 }
185
186 sz = strlen(partition);
187 p = partition + sz - 1;
188
189 if (!isdigit((unsigned int) *p))
190 goto err;
191
192 while (isdigit((unsigned int) *(p - 1))) p--;
193
194 errno = 0;
195 partno = strtol(p, &end, 10);
196 if (errno || !end || *end || p == end)
197 goto err;
198
199 return partno;
200 err:
201 errx(EXIT_FAILURE, _("%s: failed to get partition number"), partition);
202 }
203
204 static int get_max_partno(const char *disk, dev_t devno)
205 {
206 char path[PATH_MAX], *parent, *dirname = NULL;
207 struct stat st;
208 DIR *dir;
209 struct dirent *d;
210 int partno = 0;
211
212 if (!devno && !stat(disk, &st))
213 devno = st.st_rdev;
214 if (!devno)
215 goto dflt;
216 parent = strrchr(disk, '/');
217 if (!parent)
218 goto dflt;
219 parent++;
220
221 snprintf(path, sizeof(path), _PATH_SYS_DEVBLOCK "/%d:%d/",
222 major(devno), minor(devno));
223
224 dir = opendir(path);
225 if (!dir)
226 goto dflt;
227
228 dirname = xstrdup(path);
229
230 while ((d = readdir(dir))) {
231 int fd;
232
233 if (!strcmp(d->d_name, ".") ||
234 !strcmp(d->d_name, ".."))
235 continue;
236 #ifdef _DIRENT_HAVE_D_TYPE
237 if (d->d_type != DT_DIR)
238 continue;
239 #endif
240 if (strncmp(parent, d->d_name, strlen(parent)))
241 continue;
242 snprintf(path, sizeof(path), "%s/partition", d->d_name);
243
244 fd = open_at(dirfd(dir), dirname, path, O_RDONLY);
245 if (fd) {
246 int x = 0;
247 FILE *f = fdopen(fd, "r");
248 if (f) {
249 if (fscanf(f, "%d", &x) == 1 && x > partno)
250 partno = x;
251 fclose(f);
252 }
253 }
254 }
255
256 free(dirname);
257 closedir(dir);
258 return partno;
259 dflt:
260 return SLICES_MAX;
261 }
262
263 static void del_parts_warnx(const char *device, int first, int last)
264 {
265 if (first == last)
266 warnx(_("%s: error deleting partition %d"), device, first);
267 else
268 warnx(_("%s: error deleting partitions %d-%d"),
269 device, first, last);
270 }
271
272 static int del_parts(int fd, const char *device, dev_t devno,
273 int lower, int upper)
274 {
275 int rc = 0, i, errfirst = 0, errlast = 0;
276
277 assert(fd >= 0);
278 assert(device);
279
280 if (!lower)
281 lower = 1;
282 if (!upper || lower < 0 || upper < 0) {
283 int n = get_max_partno(device, devno);
284 if (!upper)
285 upper = n;
286 else if (upper < 0)
287 upper = n + upper + 1;
288 if (lower < 0)
289 lower = n + lower + 1;
290 }
291 if (lower > upper) {
292 warnx(_("specified range <%d:%d> "
293 "does not make sense"), lower, upper);
294 return -1;
295 }
296
297 for (i = lower; i <= upper; i++) {
298 rc = partx_del_partition(fd, i);
299 if (rc == 0) {
300 if (verbose)
301 printf(_("%s: partition #%d removed\n"), device, i);
302 continue;
303 } else if (errno == ENXIO) {
304 if (verbose)
305 printf(_("%s: partition #%d already doesn't exist\n"), device, i);
306 continue;
307 }
308 rc = -1;
309 if (verbose)
310 warn(_("%s: deleting partition #%d failed"), device, i);
311 if (!errfirst)
312 errlast = errfirst = i;
313 else if (errlast + 1 == i)
314 errlast++;
315 else {
316 del_parts_warnx(device, errfirst, errlast);
317 errlast = errfirst = i;
318 }
319 }
320
321 if (errfirst)
322 del_parts_warnx(device, errfirst, errlast);
323 return rc;
324 }
325
326
327 static void add_parts_warnx(const char *device, int first, int last)
328 {
329 if (first == last)
330 warnx(_("%s: error adding partition %d"), device, first);
331 else
332 warnx(_("%s: error adding partitions %d-%d"),
333 device, first, last);
334 }
335
336 static int add_parts(int fd, const char *device,
337 blkid_partlist ls, int lower, int upper)
338 {
339 int i, nparts, rc = 0, errfirst = 0, errlast = 0;
340
341 assert(fd >= 0);
342 assert(device);
343 assert(ls);
344
345 nparts = blkid_partlist_numof_partitions(ls);
346
347 for (i = 0; i < nparts; i++) {
348 blkid_partition par = blkid_partlist_get_partition(ls, i);
349 int n = blkid_partition_get_partno(par);
350 uintmax_t start, size;
351
352 if (lower && n < lower)
353 continue;
354 if (upper && n > upper)
355 continue;
356
357 start = blkid_partition_get_start(par);
358 size = blkid_partition_get_size(par);
359
360 if (blkid_partition_is_extended(par))
361 /*
362 * Let's follow the Linux kernel and reduce
363 * DOS extended partition to 1 or 2 sectors.
364 */
365 size = min(size, (uintmax_t) 2);
366
367 if (partx_add_partition(fd, n, start, size) == 0) {
368 if (verbose)
369 printf(_("%s: partition #%d added\n"), device, n);
370 continue;
371 }
372 rc = -1;
373 if (verbose)
374 warn(_("%s: adding partition #%d failed"), device, n);
375 if (!errfirst)
376 errlast = errfirst = n;
377 else if (errlast + 1 == n)
378 errlast++;
379 else {
380 add_parts_warnx(device, errfirst, errlast);
381 errlast = errfirst = n;
382 }
383 }
384
385 if (errfirst)
386 add_parts_warnx(device, errfirst, errlast);
387
388 /*
389 * The kernel with enabled partitions scanner for loop devices add *all*
390 * partitions, so we should delete any extra, unwanted ones, when the -n
391 * option is passed.
392 */
393 if (loopdev && loopcxt_is_partscan(&lc) && (lower || upper)) {
394 for (i = 0; i < nparts; i++) {
395 blkid_partition par = blkid_partlist_get_partition(ls, i);
396 int n = blkid_partition_get_partno(par);
397
398 if (n < lower || n > upper)
399 partx_del_partition(fd, n);
400 }
401 }
402
403 return rc;
404 }
405
406 static void upd_parts_warnx(const char *device, int first, int last)
407 {
408 if (first == last)
409 warnx(_("%s: error updating partition %d"), device, first);
410 else
411 warnx(_("%s: error updating partitions %d-%d"),
412 device, first, last);
413 }
414
415 static int upd_parts(int fd, const char *device, dev_t devno,
416 blkid_partlist ls, int lower, int upper)
417 {
418 int i, n, an, nparts, rc = 0, errfirst = 0, errlast = 0, err;
419 blkid_partition par;
420 uintmax_t start, size;
421
422 assert(fd >= 0);
423 assert(device);
424 assert(ls);
425
426 nparts = blkid_partlist_numof_partitions(ls);
427 if (!lower)
428 lower = 1;
429 if (!upper || lower < 0 || upper < 0) {
430 n = get_max_partno(device, devno);
431 if (!upper)
432 upper = n > nparts ? n : nparts;
433 else if (upper < 0)
434 upper = n + upper + 1;
435 if (lower < 0)
436 lower = n + lower + 1;
437 }
438 if (lower > upper) {
439 warnx(_("specified range <%d:%d> "
440 "does not make sense"), lower, upper);
441 return -1;
442 }
443
444 for (i = 0, n = lower; n <= upper; n++) {
445 par = blkid_partlist_get_partition(ls, i);
446 an = blkid_partition_get_partno(par);
447
448 if (lower && n < lower)
449 continue;
450 if (upper && n > upper)
451 continue;
452
453 start = blkid_partition_get_start(par);
454 size = blkid_partition_get_size(par);
455
456 if (blkid_partition_is_extended(par))
457 /*
458 * Let's follow the Linux kernel and reduce
459 * DOS extended partition to 1 or 2 sectors.
460 */
461 size = min(size, (uintmax_t) 2);
462
463 err = partx_del_partition(fd, n);
464 if (err == -1 && errno == ENXIO)
465 err = 0; /* good, it already doesn't exist */
466 if (an == n)
467 {
468 if (i < nparts)
469 i++;
470 if (err == -1 && errno == EBUSY)
471 {
472 /* try to resize */
473 err = partx_resize_partition(fd, n, start, size);
474 if (verbose)
475 printf(_("%s: partition #%d resized\n"), device, n);
476 if (err == 0)
477 continue;
478 }
479 if (err == 0 && partx_add_partition(fd, n, start, size) == 0) {
480 if (verbose)
481 printf(_("%s: partition #%d added\n"), device, n);
482 continue;
483 }
484 }
485 if (err == 0)
486 continue;
487 rc = -1;
488 if (verbose)
489 warn(_("%s: updating partition #%d failed"), device, n);
490 if (!errfirst)
491 errlast = errfirst = n;
492 else if (errlast + 1 == n)
493 errlast++;
494 else {
495 upd_parts_warnx(device, errfirst, errlast);
496 errlast = errfirst = n;
497 }
498 }
499
500 if (errfirst)
501 upd_parts_warnx(device, errfirst, errlast);
502 return rc;
503 }
504
505 static int list_parts(blkid_partlist ls, int lower, int upper)
506 {
507 int i, nparts;
508
509 assert(ls);
510
511 nparts = blkid_partlist_numof_partitions(ls);
512
513 for (i = 0; i < nparts; i++) {
514 blkid_partition par = blkid_partlist_get_partition(ls, i);
515 int n = blkid_partition_get_partno(par);
516 uintmax_t start, size;
517
518 if (lower && n < lower)
519 continue;
520 if (upper && n > upper)
521 continue;
522
523 start = blkid_partition_get_start(par);
524 size = blkid_partition_get_size(par);
525
526 printf(_("#%2d: %9ju-%9ju (%9ju sectors, %6ju MB)\n"),
527 n, start, start + size -1,
528 size, (size << 9) / 1000000);
529 }
530 return 0;
531 }
532
533 static void add_tt_line(struct tt *tt, blkid_partition par)
534 {
535 struct tt_line *line;
536 int i;
537
538 assert(tt);
539 assert(par);
540
541 line = tt_add_line(tt, NULL);
542 if (!line) {
543 warn(_("failed to add line to output"));
544 return;
545 }
546
547 for (i = 0; i < ncolumns; i++) {
548 char *str = NULL;
549
550 switch (get_column_id(i)) {
551 case COL_PARTNO:
552 xasprintf(&str, "%d", blkid_partition_get_partno(par));
553 break;
554 case COL_START:
555 xasprintf(&str, "%ju", blkid_partition_get_start(par));
556 break;
557 case COL_END:
558 xasprintf(&str, "%ju",
559 blkid_partition_get_start(par) +
560 blkid_partition_get_size(par) - 1);
561 break;
562 case COL_SECTORS:
563 xasprintf(&str, "%ju", blkid_partition_get_size(par));
564 break;
565 case COL_SIZE:
566 if (partx_flags & FL_BYTES)
567 xasprintf(&str, "%ju", (uintmax_t)
568 blkid_partition_get_size(par) << 9);
569 else
570 str = size_to_human_string(SIZE_SUFFIX_1LETTER,
571 blkid_partition_get_size(par) << 9);
572 break;
573 case COL_NAME:
574 str = (char *) blkid_partition_get_name(par);
575 if (str)
576 str = xstrdup(str);
577 break;
578 case COL_UUID:
579 str = (char *) blkid_partition_get_uuid(par);
580 if (str)
581 str = xstrdup(str);
582 break;
583 case COL_TYPE:
584 str = (char *) blkid_partition_get_type_string(par);
585 if (str)
586 str = xstrdup(str);
587 else
588 xasprintf(&str, "0x%x",
589 blkid_partition_get_type(par));
590 break;
591 case COL_FLAGS:
592 xasprintf(&str, "0x%llx", blkid_partition_get_flags(par));
593 break;
594 case COL_SCHEME:
595 {
596 blkid_parttable tab = blkid_partition_get_table(par);
597 if (tab) {
598 str = (char *) blkid_parttable_get_type(tab);
599 if (str)
600 str = xstrdup(str);
601 }
602 break;
603 }
604 default:
605 break;
606 }
607
608 if (str)
609 tt_line_set_data(line, i, str);
610 }
611 }
612
613 static int show_parts(blkid_partlist ls, int tt_flags, int lower, int upper)
614 {
615 int i, rc = -1;
616 struct tt *tt;
617 int nparts;
618
619 assert(ls);
620
621 nparts = blkid_partlist_numof_partitions(ls);
622 if (!nparts)
623 return 0;
624
625 tt = tt_new_table(tt_flags);
626 if (!tt) {
627 warn(_("failed to initialize output table"));
628 return -1;
629 }
630
631 for (i = 0; i < ncolumns; i++) {
632 struct colinfo *col = get_column_info(i);
633
634 if (!tt_define_column(tt, col->name, col->whint, col->flags)) {
635 warnx(_("failed to initialize output column"));
636 goto done;
637 }
638 }
639
640 for (i = 0; i < nparts; i++) {
641 blkid_partition par = blkid_partlist_get_partition(ls, i);
642 int n = blkid_partition_get_partno(par);
643
644 if (lower && n < lower)
645 continue;
646 if (upper && n > upper)
647 continue;
648
649 add_tt_line(tt, par);
650 }
651
652 rc = 0;
653 tt_print_table(tt);
654 done:
655 tt_free_table(tt);
656 return rc;
657 }
658
659 static blkid_partlist get_partlist(blkid_probe pr,
660 const char *device, char *type)
661 {
662 blkid_partlist ls;
663 blkid_parttable tab;
664
665 assert(pr);
666 assert(device);
667
668 if (type) {
669 char *name[] = { type, NULL };
670
671 if (blkid_probe_filter_partitions_type(pr,
672 BLKID_FLTR_ONLYIN, name)) {
673 warnx(_("failed to initialize blkid "
674 "filter for '%s'"), type);
675 return NULL;
676 }
677 }
678
679 ls = blkid_probe_get_partitions(pr);
680 if (!ls) {
681 warnx(_("%s: failed to read partition table"), device);
682 return NULL;
683 }
684
685 tab = blkid_partlist_get_table(ls);
686 if (verbose && tab) {
687 printf(_("%s: partition table type '%s' detected\n"),
688 device, blkid_parttable_get_type(tab));
689
690 if (!blkid_partlist_numof_partitions(ls))
691 printf(_("%s: partition table with no partitions"), device);
692 }
693
694 return ls;
695 }
696
697 static void __attribute__((__noreturn__)) usage(FILE *out)
698 {
699 size_t i;
700
701 fputs(USAGE_HEADER, out);
702 fprintf(out,
703 _(" %s [-a|-d|-s|-u] [--nr <n:m> | <partition>] <disk>\n"),
704 program_invocation_short_name);
705
706 fputs(USAGE_OPTIONS, out);
707 fputs(_(" -a, --add add specified partitions or all of them\n"), out);
708 fputs(_(" -d, --delete delete specified partitions or all of them\n"), out);
709 fputs(_(" -s, --show list partitions\n\n"), out);
710 fputs(_(" -u, --update update specified partitions or all of them\n"), out);
711 fputs(_(" -b, --bytes print SIZE in bytes rather than in human readable format\n"), out);
712 fputs(_(" -g, --noheadings don't print headings for --show\n"), out);
713 fputs(_(" -n, --nr <n:m> specify the range of partitions (e.g. --nr 2:4)\n"), out);
714 fputs(_(" -o, --output <type> define which output columns to use\n"), out);
715 fputs(_(" -P, --pairs use key=\"value\" output format\n"), out);
716 fputs(_(" -r, --raw use raw output format\n"), out);
717 fputs(_(" -t, --type <type> specify the partition type (dos, bsd, solaris, etc.)\n"), out);
718 fputs(_(" -v, --verbose verbose mode\n"), out);
719
720 fputs(USAGE_SEPARATOR, out);
721 fputs(USAGE_HELP, out);
722 fputs(USAGE_VERSION, out);
723
724 fputs(_("\nAvailable columns (for --show, --raw or --pairs):\n"), out);
725
726 for (i = 0; i < NCOLS; i++)
727 fprintf(out, " %10s %s\n", infos[i].name, _(infos[i].help));
728
729 fprintf(out, USAGE_MAN_TAIL("partx(8)"));
730
731 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
732 }
733
734 int main(int argc, char **argv)
735 {
736 int fd, c, what = ACT_NONE, lower = 0, upper = 0, rc = 0;
737 int tt_flags = 0;
738 char *type = NULL;
739 char *device = NULL; /* pointer to argv[], ie: /dev/sda1 */
740 char *wholedisk = NULL; /* allocated, ie: /dev/sda */
741 char *outarg = NULL;
742 dev_t disk_devno = 0, part_devno = 0;
743
744 static const struct option long_opts[] = {
745 { "bytes", no_argument, NULL, 'b' },
746 { "noheadings", no_argument, NULL, 'g' },
747 { "raw", no_argument, NULL, 'r' },
748 { "list", no_argument, NULL, 'l' },
749 { "show", no_argument, NULL, 's' },
750 { "add", no_argument, NULL, 'a' },
751 { "delete", no_argument, NULL, 'd' },
752 { "update", no_argument, NULL, 'u' },
753 { "type", required_argument, NULL, 't' },
754 { "nr", required_argument, NULL, 'n' },
755 { "output", required_argument, NULL, 'o' },
756 { "pairs", no_argument, NULL, 'P' },
757 { "help", no_argument, NULL, 'h' },
758 { "version", no_argument, NULL, 'V' },
759 { "verbose", no_argument, NULL, 'v' },
760 { NULL, 0, NULL, 0 }
761 };
762
763 static const ul_excl_t excl[] = { /* rows and cols in in ASCII order */
764 { 'P','a','d','l','r','s' },
765 { 0 }
766 };
767 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
768
769 setlocale(LC_ALL, "");
770 bindtextdomain(PACKAGE, LOCALEDIR);
771 textdomain(PACKAGE);
772 atexit(close_stdout);
773
774 while ((c = getopt_long(argc, argv,
775 "abdglrsuvn:t:o:PhV", long_opts, NULL)) != -1) {
776
777 err_exclusive_options(c, long_opts, excl, excl_st);
778
779 switch(c) {
780 case 'a':
781 what = ACT_ADD;
782 break;
783 case 'b':
784 partx_flags |= FL_BYTES;
785 break;
786 case 'd':
787 what = ACT_DELETE;
788 break;
789 case 'g':
790 tt_flags |= TT_FL_NOHEADINGS;
791 break;
792 case 'l':
793 what = ACT_LIST;
794 break;
795 case 'n':
796 if (parse_range(optarg, &lower, &upper, 0))
797 errx(EXIT_FAILURE, _("failed to parse --nr <M-N> range"));
798 break;
799 case 'o':
800 outarg = optarg;
801 break;
802 case 'P':
803 tt_flags |= TT_FL_EXPORT;
804 what = ACT_SHOW;
805 break;
806 case 'r':
807 tt_flags |= TT_FL_RAW;
808 what = ACT_SHOW;
809 break;
810 case 's':
811 what = ACT_SHOW;
812 break;
813 case 't':
814 type = optarg;
815 break;
816 case 'u':
817 what = ACT_UPD;
818 break;
819 case 'v':
820 verbose = 1;
821 break;
822 case 'h':
823 usage(stdout);
824 case 'V':
825 printf(UTIL_LINUX_VERSION);
826 return EXIT_SUCCESS;
827 case '?':
828 default:
829 usage(stderr);
830 }
831 }
832
833 if (what == ACT_NONE)
834 what = ACT_SHOW;
835
836 /* --show default, could by modified by -o */
837 if (what == ACT_SHOW && !ncolumns) {
838 columns[ncolumns++] = COL_PARTNO;
839 columns[ncolumns++] = COL_START;
840 columns[ncolumns++] = COL_END;
841 columns[ncolumns++] = COL_SECTORS;
842 columns[ncolumns++] = COL_SIZE;
843 columns[ncolumns++] = COL_NAME;
844 columns[ncolumns++] = COL_UUID;
845 }
846
847 if (what == ACT_SHOW && outarg &&
848 string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
849 &ncolumns, column_name_to_id) < 0)
850 return EXIT_FAILURE;
851
852 /*
853 * Note that 'partx /dev/sda1' == 'partx /dev/sda1 /dev/sda'
854 * so assume that the device and/or disk are always the last
855 * arguments to be passed to partx.
856 */
857 if (optind == argc - 2) {
858 /* passed 2 arguments:
859 * /dev/sda1 /dev/sda : partition + whole-disk
860 * -- /dev/sda1 : partition that should be used as a whole-disk
861 */
862 device = argv[optind];
863
864 if (strcmp(device, "-") == 0) {
865 device = NULL;
866 wholedisk = xstrdup(argv[optind + 1]);
867 } else {
868 device = argv[optind];
869 wholedisk = xstrdup(argv[optind + 1]);
870 }
871 } else if (optind == argc - 1) {
872 /* passed only one arg (ie: /dev/sda3 or /dev/sda) */
873 struct stat sb;
874
875 device = argv[optind];
876
877 if (stat(device, &sb))
878 err(EXIT_FAILURE, _("stat failed %s"), device);
879
880 part_devno = sb.st_rdev;
881
882 if (blkid_devno_to_wholedisk(part_devno,
883 NULL, 0, &disk_devno) == 0 &&
884 part_devno != disk_devno)
885 wholedisk = blkid_devno_to_devname(disk_devno);
886
887 if (!wholedisk) {
888 wholedisk = xstrdup(device);
889 disk_devno = part_devno;
890 device = NULL;
891 part_devno = 0;
892 }
893 } else
894 usage(stderr);
895
896 if (device && (upper || lower))
897 errx(EXIT_FAILURE, _("--nr and <partition> are mutually exclusive"));
898
899 assert(wholedisk);
900
901 if (device) {
902 /* use partno from given partition instead of --nr range, e.g:
903 * partx -d /dev/sda3
904 * is the same like:
905 * partx -d --nr 3 /dev/sda
906 */
907 struct stat sb;
908
909 if (!part_devno && !stat(device, &sb))
910 part_devno = sb.st_rdev;
911
912 lower = upper = get_partno_from_device(device, part_devno);
913 }
914
915 if (verbose)
916 printf(_("partition: %s, disk: %s, lower: %d, upper: %d\n"),
917 device ? device : "none", wholedisk, lower, upper);
918
919 if (what == ACT_ADD || what == ACT_DELETE) {
920 struct stat x;
921
922 if (stat(wholedisk, &x))
923 errx(EXIT_FAILURE, "%s", wholedisk);
924
925 if (S_ISREG(x.st_mode)) {
926 /* not a blkdev, try to associate it to a loop device */
927 if (what == ACT_DELETE)
928 errx(EXIT_FAILURE, _("%s: cannot delete partitions"),
929 wholedisk);
930 if (!loopmod_supports_partscan())
931 errx(EXIT_FAILURE, _("%s: partitioned loop devices unsupported"),
932 wholedisk);
933 assoc_loopdev(wholedisk);
934 wholedisk = xstrdup(lc.device);
935 } else if (!S_ISBLK(x.st_mode))
936 errx(EXIT_FAILURE, _("%s: not a block device"), wholedisk);
937 }
938 if ((fd = open(wholedisk, O_RDONLY)) == -1)
939 err(EXIT_FAILURE, _("cannot open %s"), wholedisk);
940
941 if (what == ACT_DELETE)
942 rc = del_parts(fd, wholedisk, disk_devno, lower, upper);
943 else {
944 blkid_probe pr = blkid_new_probe();
945 blkid_partlist ls = NULL;
946
947 if (!pr || blkid_probe_set_device(pr, fd, 0, 0))
948 warnx(_("%s: failed to initialize blkid prober"),
949 wholedisk);
950 else
951 ls = get_partlist(pr, wholedisk, type);
952
953 if (ls) {
954 int n = blkid_partlist_numof_partitions(ls);
955
956 if (lower < 0)
957 lower = n + lower + 1;
958 if (upper < 0)
959 upper = n + upper + 1;
960 if (lower > upper) {
961 warnx(_("specified range <%d:%d> "
962 "does not make sense"), lower, upper);
963 rc = -1, what = ACT_NONE;
964 }
965
966 switch (what) {
967 case ACT_SHOW:
968 rc = show_parts(ls, tt_flags, lower, upper);
969 break;
970 case ACT_LIST:
971 rc = list_parts(ls, lower, upper);
972 break;
973 case ACT_ADD:
974 rc = add_parts(fd, wholedisk, ls, lower, upper);
975 break;
976 case ACT_UPD:
977 rc = upd_parts(fd, wholedisk, disk_devno, ls, lower, upper);
978 case ACT_NONE:
979 break;
980 default:
981 abort();
982 }
983 }
984 blkid_free_probe(pr);
985 }
986
987 if (loopdev)
988 loopcxt_deinit(&lc);
989
990 close(fd);
991 return rc ? EXIT_FAILURE : EXIT_SUCCESS;
992 }