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