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