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