]> git.ipfire.org Git - thirdparty/util-linux.git/blame - partx/partx.c
textual: improve the wording of some error and usage messages
[thirdparty/util-linux.git] / partx / partx.c
CommitLineData
22853e4a 1/*
c4ecaf21 2 * partx: tell the kernel about your disk's partitions
22853e4a
KZ
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 *
22853e4a 7 * aeb, 2000-03-21 -- sah is 42 now
c4ecaf21
DB
8 *
9 * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
a9485396 10 * Rewritten to use libblkid for util-linux
c4ecaf21 11 * based on ideas from Karel Zak <kzak@redhat.com>
22853e4a
KZ
12 */
13
14#include <stdio.h>
15#include <fcntl.h>
16#include <errno.h>
17#include <stdlib.h>
18#include <string.h>
c4ecaf21 19#include <ctype.h>
22853e4a 20#include <getopt.h>
c4ecaf21
DB
21#include <sys/types.h>
22#include <sys/stat.h>
1d4ad1de 23#include <unistd.h>
c4ecaf21 24#include <assert.h>
22853e4a 25#include <sys/ioctl.h>
22853e4a 26#include <linux/blkpg.h>
c4ecaf21
DB
27#include <dirent.h>
28
29#include <blkid.h>
0d518f34 30
1aff9b62 31#include "c.h"
c4ecaf21
DB
32#include "pathnames.h"
33#include "nls.h"
34#include "tt.h"
0d518f34 35#include "blkdev.h"
c4ecaf21
DB
36#include "strutils.h"
37#include "xalloc.h"
22853e4a 38#include "partx.h"
22853e4a 39
c4ecaf21
DB
40/* this is the default upper limit, could be modified by --nr */
41#define SLICES_MAX 256
42
43/* all the columns (-o option) */
44enum {
45 COL_PARTNO,
46 COL_START,
47 COL_END,
48 COL_SECTORS,
49 COL_SIZE,
50 COL_NAME,
51 COL_UUID,
52 COL_TYPE,
5de966b3
KZ
53 COL_FLAGS,
54 COL_SCHEME,
c4ecaf21
DB
55 __NCOLUMNS
56};
22853e4a 57
c4ecaf21
DB
58enum {
59 ACT_LIST = 1,
60 ACT_SHOW,
61 ACT_ADD,
62 ACT_DELETE
63};
64
65enum {
66 FL_BYTES = (1 << 1)
67};
68
69/* column names */
70struct 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};
22853e4a 76
c4ecaf21
DB
77/* columns descriptions */
78struct colinfo infos[__NCOLUMNS] = {
5de966b3 79 [COL_PARTNO] = { "NR", 0.25, TT_FL_RIGHT, N_("partition number") },
c4ecaf21
DB
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")},
5de966b3
KZ
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")},
c4ecaf21
DB
89};
90/* array with IDs of enabled columns */
91static int columns[__NCOLUMNS], ncolumns;
92
93static int verbose;
94static int partx_flags;
22853e4a 95
22853e4a 96
c4ecaf21 97static inline int get_column_id(int num)
1d4ad1de 98{
c4ecaf21
DB
99 assert(ARRAY_SIZE(columns) == __NCOLUMNS);
100 assert(num < ncolumns);
101 assert(columns[num] < __NCOLUMNS);
102 return columns[num];
22853e4a
KZ
103}
104
c4ecaf21 105static inline struct colinfo *get_column_info(int num)
1d4ad1de 106{
c4ecaf21 107 return &infos[ get_column_id(num) ];
22853e4a
KZ
108}
109
c4ecaf21
DB
110static int column_name_to_id(const char *name, size_t namesz)
111{
112 int i;
22853e4a 113
c4ecaf21 114 assert(name);
22853e4a 115
c4ecaf21
DB
116 for (i = 0; i < __NCOLUMNS; i++) {
117 const char *cn = infos[i].name;
22853e4a 118
c4ecaf21
DB
119 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
120 return i;
22853e4a 121 }
c4ecaf21
DB
122 warnx(_("unknown column: %s"), name);
123 return -1;
124}
22853e4a 125
c4ecaf21
DB
126/*
127 * Given a partition return the corresponding partition number.
128 *
129 * Note that this function tries to use sysfs, otherwise it assumes that the
130 * last characters are always numeric (sda1, sdc20, etc).
131 *
132 * Returns -1 on error.
133 */
134static int get_partno_from_device(char *partition, dev_t devno)
135{
136 int partno = 0;
137 size_t sz;
138 char *p, *end = NULL;
139
140 assert(partition);
141
142 if (devno) {
143 /* the device exits, read the partition number from /sys
144 * TODO: move this to stuff to lib/sysfs.c */
145 char path[PATH_MAX];
146 FILE *f;
147
148 snprintf(path, sizeof(path),
149 _PATH_SYS_DEVBLOCK "/%d:%d/partition",
150 major(devno), minor(devno));
151 f = fopen(path, "r");
152 if (f) {
153 if (fscanf(f, "%d", &partno) != 1)
154 partno = 0;
155 fclose(f);
22853e4a 156 }
c4ecaf21
DB
157 if (partno)
158 return partno;
159 }
22853e4a 160
c4ecaf21
DB
161 sz = strlen(partition);
162 p = partition + sz - 1;
22853e4a 163
c4ecaf21
DB
164 if (!isdigit((unsigned int) *p))
165 goto err;
22853e4a 166
c4ecaf21
DB
167 while (isdigit((unsigned int) *(p - 1))) p--;
168
169 errno = 0;
170 partno = strtol(p, &end, 10);
171 if (errno || !end || *end || p == end)
172 goto err;
173
174 return partno;
175err:
176 errx(EXIT_FAILURE, _("%s: failed to get partition number"), partition);
177}
178
179static int get_max_partno(const char *disk, dev_t devno)
180{
181 char path[PATH_MAX], *parent;
182 struct stat st;
183 DIR *dir;
184 struct dirent *d;
185 int partno = 0;
186
187 if (!devno && !stat(disk, &st))
188 devno = st.st_rdev;
189 if (!devno)
190 goto dflt;
191 parent = strrchr(disk, '/');
192 if (!parent)
193 goto dflt;
194 parent++;
195
196 snprintf(path, sizeof(path), _PATH_SYS_DEVBLOCK "/%d:%d/",
197 major(devno), minor(devno));
198
199 dir = opendir(path);
200 if (!dir)
201 goto dflt;
202
203 while ((d = readdir(dir))) {
204 int fd;
205
206 if (!strcmp(d->d_name, ".") ||
207 !strcmp(d->d_name, ".."))
208 continue;
209#ifdef _DIRENT_HAVE_D_TYPE
210 if (d->d_type != DT_DIR)
211 continue;
212#endif
213 if (strncmp(parent, d->d_name, strlen(parent)))
214 continue;
215 snprintf(path, sizeof(path), "%s/partition", d->d_name);
216
217 fd = openat(dirfd(dir), path, O_RDONLY);
218 if (fd) {
219 int x = 0;
220 FILE *f = fdopen(fd, "r");
221 if (f) {
222 if (fscanf(f, "%d", &x) == 1 && x > partno)
223 partno = x;
224 fclose(f);
22853e4a 225 }
22853e4a 226 }
22853e4a
KZ
227 }
228
c4ecaf21
DB
229 closedir(dir);
230 return partno;
231dflt:
232 return SLICES_MAX;
233}
234
235static void del_parts_warnx(const char *device, int first, int last)
236{
237 if (first == last)
238 warnx(_("%s: error deleting partition %d"), device, first);
239 else
240 warnx(_("%s: error deleting partitions %d-%d"),
241 device, first, last);
242}
243
244static int del_parts(int fd, const char *device, dev_t devno,
245 int lower, int upper)
246{
247 int rc = 0, i, errfirst = 0, errlast = 0;
248
249 assert(fd >= 0);
250 assert(device);
251
252 if (!lower)
253 lower = 1;
254 if (!upper || lower < 0 || upper < 0) {
255 int n = get_max_partno(device, devno);
256 if (!upper)
257 upper = n;
258 else if (upper < 0)
259 upper = n + upper + 1;
260 if (lower < 0)
261 lower = n + lower + 1;
262 }
263 if (lower > upper) {
264 warnx(_("defined range <%d:%d> "
265 "does not make sense"), lower, upper);
266 return -1;
267 }
268
269 for (i = lower; i <= upper; i++) {
270 if (partx_del_partition(fd, i) == 0) {
271 if (verbose)
272 printf(_("%s: partition #%d removed\n"), device, i);
273 continue;
274 }
275 rc = -1;
276 if (verbose)
277 warn(_("%s: delete partition #%d failed"), device, i);
278 if (!errfirst)
279 errlast = errfirst = i;
280 else if (errlast + 1 == i)
281 errlast++;
282 else {
283 del_parts_warnx(device, errfirst, errlast);
284 errlast = errfirst = i;
22853e4a 285 }
22853e4a
KZ
286 }
287
c4ecaf21
DB
288 if (errfirst)
289 del_parts_warnx(device, errfirst, errlast);
290 return rc;
291}
292
293static void add_parts_warnx(const char *device, int first, int last)
294{
295 if (first == last)
296 warnx(_("%s: error adding partition %d"), device, first);
297 else
298 warnx(_("%s: error adding partitions %d-%d"),
299 device, first, last);
300}
301
302static int add_parts(int fd, const char *device,
303 blkid_partlist ls, int lower, int upper)
304{
305 int i, nparts, rc = 0, errfirst = 0, errlast = 0;
306
307 assert(fd >= 0);
308 assert(device);
309 assert(ls);
310
311 nparts = blkid_partlist_numof_partitions(ls);
312
313 for (i = 0; i < nparts; i++) {
314 blkid_partition par = blkid_partlist_get_partition(ls, i);
315 int n = blkid_partition_get_partno(par);
316 uintmax_t start, size;
317
318 if (lower && n < lower)
319 continue;
320 if (upper && n > upper)
321 continue;
322
323 start = blkid_partition_get_start(par);
324 size = blkid_partition_get_size(par);
325
326 if (blkid_partition_is_extended(par))
327 /*
328 * Let's follow Linux kernel and reduce
329 * DOS extended partition to 1 or 2 sectors
330 */
331 size = min(size, (uintmax_t) 2);
332
333 if (partx_add_partition(fd, n, start, size) == 0) {
334 if (verbose)
335 printf(_("%s: partition #%d added\n"), device, n);
336 continue;
337 }
338 rc = -1;
339 if (verbose)
340 warn(_("%s: add partition #%d failed"), device, n);
341 if (!errfirst)
342 errlast = errfirst = n;
343 else if (errlast + 1 == n)
344 errlast++;
345 else {
346 add_parts_warnx(device, errfirst, errlast);
347 errlast = errfirst = n;
348 }
22853e4a 349 }
c4ecaf21
DB
350
351 if (errfirst)
352 add_parts_warnx(device, errfirst, errlast);
353 return rc;
354}
355
356static int list_parts(blkid_partlist ls, int lower, int upper)
357{
358 int i, nparts;
359
360 assert(ls);
361
362 nparts = blkid_partlist_numof_partitions(ls);
363
364 for (i = 0; i < nparts; i++) {
365 blkid_partition par = blkid_partlist_get_partition(ls, i);
366 int n = blkid_partition_get_partno(par);
367 uintmax_t start, size;
368
369 if (lower && n < lower)
370 continue;
371 if (upper && n > upper)
372 continue;
373
374 start = blkid_partition_get_start(par);
375 size = blkid_partition_get_size(par);
376
377 printf("#%2d: %9ju-%9ju (%9ju sectors, %6ju MB)\n",
378 n, start, start + size -1,
379 size, (size << 9) / 1000000);
22853e4a 380 }
c4ecaf21
DB
381 return 0;
382}
383
384static void add_tt_line(struct tt *tt, blkid_partition par)
385{
386 struct tt_line *line;
387 int i;
388
389 assert(tt);
390 assert(par);
22853e4a 391
c4ecaf21
DB
392 line = tt_add_line(tt, NULL);
393 if (!line) {
394 warn(_("failed to add line to output"));
395 return;
22853e4a 396 }
22853e4a 397
c4ecaf21
DB
398 for (i = 0; i < ncolumns; i++) {
399 char *str = NULL;
400 int rc = 0;
401
402 switch (get_column_id(i)) {
403 case COL_PARTNO:
404 rc = asprintf(&str, "%d",
405 blkid_partition_get_partno(par));
406 break;
407 case COL_START:
408 rc = asprintf(&str, "%ju",
409 blkid_partition_get_start(par));
410 break;
411 case COL_END:
412 rc = asprintf(&str, "%ju",
413 blkid_partition_get_start(par) +
414 blkid_partition_get_size(par) - 1);
415 break;
416 case COL_SECTORS:
417 rc = asprintf(&str, "%ju",
418 blkid_partition_get_size(par));
419 break;
420 case COL_SIZE:
421 if (partx_flags & FL_BYTES)
422 rc = asprintf(&str, "%ju", (uintmax_t)
423 blkid_partition_get_size(par) << 9);
5de966b3 424 else
c4ecaf21
DB
425 str = size_to_human_string(
426 blkid_partition_get_size(par) << 9);
c4ecaf21
DB
427 break;
428 case COL_NAME:
429 str = (char *) blkid_partition_get_name(par);
5de966b3
KZ
430 if (str)
431 str = xstrdup(str);
c4ecaf21
DB
432 break;
433 case COL_UUID:
434 str = (char *) blkid_partition_get_uuid(par);
5de966b3
KZ
435 if (str)
436 str = xstrdup(str);
c4ecaf21
DB
437 break;
438 case COL_TYPE:
5de966b3
KZ
439 str = (char *) blkid_partition_get_type_string(par);
440 if (str)
441 str = xstrdup(str);
442 else
443 rc = asprintf(&str, "0x%x",
444 blkid_partition_get_type(par));
c4ecaf21 445 break;
5de966b3
KZ
446 case COL_FLAGS:
447 rc = asprintf(&str, "0x%llx", blkid_partition_get_flags(par));
448 break;
449 case COL_SCHEME:
450 {
451 blkid_parttable tab = blkid_partition_get_table(par);
452 if (tab) {
453 str = (char *) blkid_parttable_get_type(tab);
454 if (str)
455 str = xstrdup(str);
456 }
457 break;
458 }
c4ecaf21
DB
459 default:
460 break;
461 }
462
5de966b3 463 if (rc || str)
c4ecaf21 464 tt_line_set_data(line, i, str);
22853e4a 465 }
c4ecaf21 466}
22853e4a 467
c4ecaf21
DB
468static int show_parts(blkid_partlist ls, int tt_flags, int lower, int upper)
469{
470 int i, rc = -1;
471 struct tt *tt;
472 int nparts;
22853e4a 473
c4ecaf21
DB
474 assert(ls);
475
476 nparts = blkid_partlist_numof_partitions(ls);
477 if (!nparts)
478 return 0;
479
480 tt = tt_new_table(tt_flags);
481 if (!tt) {
482 warn(_("failed to initialize output table"));
483 return -1;
22853e4a 484 }
22853e4a 485
c4ecaf21
DB
486 for (i = 0; i < ncolumns; i++) {
487 struct colinfo *col = get_column_info(i);
488
489 if (!tt_define_column(tt, col->name, col->whint, col->flags)) {
490 warnx(_("failed to initialize output column"));
491 goto done;
22853e4a
KZ
492 }
493 }
494
c4ecaf21
DB
495 for (i = 0; i < nparts; i++) {
496 blkid_partition par = blkid_partlist_get_partition(ls, i);
497 int n = blkid_partition_get_partno(par);
22853e4a 498
c4ecaf21
DB
499 if (lower && n < lower)
500 continue;
501 if (upper && n > upper)
502 continue;
22853e4a 503
c4ecaf21 504 add_tt_line(tt, par);
22853e4a 505 }
c4ecaf21
DB
506
507 rc = 0;
508 tt_print_table(tt);
509done:
510 tt_free_table(tt);
511 return rc;
22853e4a
KZ
512}
513
c4ecaf21
DB
514static int parse_range(const char *str, int *lower, int *upper)
515{
516 char *end = NULL;
517
518 if (!str)
519 return 0;
22853e4a 520
c4ecaf21
DB
521 *upper = *lower = 0;
522 errno = 0;
523
524 if (*str == ':') { /* <:N> */
525 str++;
526 *upper = strtol(str, &end, 10);
527 if (errno || !end || *end || end == str)
528 return -1;
529 } else {
530 *upper = *lower = strtol(str, &end, 10);
531 if (errno || !end || end == str)
532 return -1;
533
534 if (*end == ':' && !*(end + 1)) /* <M:> */
535 *upper = 0;
536 else if (*end == '-' || *end == ':') { /* <M:N> <M-N> */
537 str = end + 1;
538 end = NULL;
539 errno = 0;
540 *upper = strtol(str, &end, 10);
541
542 if (errno || !end || *end || end == str)
543 return -1;
544 }
22853e4a
KZ
545 }
546 return 0;
547}
548
c4ecaf21
DB
549static blkid_partlist get_partlist(blkid_probe pr,
550 const char *device, char *type)
551{
552 blkid_partlist ls;
553 blkid_parttable tab;
554
555 assert(pr);
556 assert(device);
557
558 if (type) {
559 char *name[] = { type, NULL };
560
561 if (blkid_probe_filter_partitions_type(pr,
562 BLKID_FLTR_ONLYIN, name)) {
563 warnx(_("failed to initialize blkid "
564 "filter for '%s'"), type);
565 return NULL;
566 }
567 }
568
569 ls = blkid_probe_get_partitions(pr);
570 if (!ls) {
571 warnx(_("%s: failed to read partition table"), device);
572 return NULL;
573 }
574
575 tab = blkid_partlist_get_table(ls);
576 if (verbose && tab)
577 printf(_("%s: partition table '%s' detected\n"),
578 device,
579 blkid_parttable_get_type(tab));
580
581 if (!blkid_partlist_numof_partitions(ls)) {
582 warnx(_("%s: %s partition table does not contains "
583 "usable partitions"), device,
584 blkid_parttable_get_type(tab));
22853e4a 585 return NULL;
22853e4a 586 }
c4ecaf21
DB
587 return ls;
588}
589
abafd686 590static void __attribute__((__noreturn__)) usage(FILE *out)
c4ecaf21
DB
591{
592 int i;
593
594 fprintf(out, _(
595 "\nUsage:\n"
e8ab5ce3 596 " %s [-a|-d|-s] [--nr <N:M> | <partition>] <disk>\n"),
c4ecaf21
DB
597 program_invocation_short_name);
598
599 fprintf(out, _(
600 "\nOptions:\n"
601 " -a, --add add specified partitions or all of them\n"
602 " -d, --delete delete specified partitions or all of them\n"
603 " -l, --list list partitions (DEPRECATED)\n"
604 " -s, --show list partitions\n\n"
605
606 " -b, --bytes print SIZE in bytes rather than in human readable format\n"
607 " -g, --noheadings don't print headings for --show\n"
608 " -r, --raw use raw format output\n"
609 " -t, --type <TYPE> specify the partition type (dos, bsd, solaris, etc.)\n"
e8ab5ce3
BS
610 " -n, --nr <M:N> specify the range of partitions (e.g. --nr 2:4)\n"
611 " -o, --output <LIST> define which output columns to use\n"
c4ecaf21
DB
612 " -h, --help print this help\n\n"));
613
614 fprintf(out, _("\nAvailable columns (for --show):\n"));
615
616 for (i = 0; i < __NCOLUMNS; i++)
d015794e 617 fprintf(out, " %10s %s\n", infos[i].name, _(infos[i].help));
c4ecaf21
DB
618
619 fprintf(out, _("\nFor more information see partx(8).\n"));
620
621 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
622}
623
abafd686 624static void __attribute__((__noreturn__))
c4ecaf21
DB
625errx_mutually_exclusive(const char *opts)
626{
627 errx(EXIT_FAILURE, "%s %s", opts, _("options are mutually exclusive"));
22853e4a
KZ
628}
629
c4ecaf21
DB
630int main(int argc, char **argv)
631{
632 int fd, c, what = 0, lower = 0, upper = 0, rc = 0;
633 int tt_flags = 0;
634 char *type = NULL;
635 char *device = NULL; /* pointer to atgv[], ie: /dev/sda1 */
636 char *wholedisk = NULL; /* allocated, ie: /dev/sda */
637 dev_t disk_devno = 0, part_devno = 0;
638
639 static const struct option long_opts[] = {
640 { "bytes", no_argument, NULL, 'b' },
641 { "noheadings", no_argument, NULL, 'g' },
642 { "raw", no_argument, NULL, 'r' },
643 { "list", no_argument, NULL, 'l' },
644 { "show", no_argument, NULL, 's' },
645 { "add", no_argument, NULL, 'a' },
646 { "delete", no_argument, NULL, 'd' },
647 { "type", required_argument, NULL, 't' },
648 { "nr", required_argument, NULL, 'n' },
649 { "output", required_argument, NULL, 'o' },
650 { "help", no_argument, NULL, 'h' },
651 { NULL, 0, NULL, 0 }
652 };
653
654 while ((c = getopt_long(argc, argv, "abdglrsvn:t:o:h", long_opts, NULL)) != -1) {
655 switch(c) {
656 case 'a':
657 if (what)
658 errx_mutually_exclusive("--{add,delete,show,list,raw}");
659 what = ACT_ADD;
660 break;
661 case 'b':
662 partx_flags |= FL_BYTES;
663 break;
664 case 'd':
665 if (what)
666 errx_mutually_exclusive("--{add,delete,show,list,raw}");
667 what = ACT_DELETE;
668 break;
669 case 'g':
670 tt_flags |= TT_FL_NOHEADINGS;
671 break;
672 case 'l':
673 if (what)
674 errx_mutually_exclusive("--{add,delete,show,list,raw}");
675 what = ACT_LIST;
676 break;
677 case 'n':
678 if (parse_range(optarg, &lower, &upper))
679 errx(EXIT_FAILURE, _("failed to parse --nr <M-N> range"));
680 break;
681
682 case 'o':
683 if (tt_parse_columns_list(optarg, columns, &ncolumns,
684 column_name_to_id))
685 return EXIT_FAILURE;
686 break;
687 case 'r':
688 tt_flags |= TT_FL_RAW;
689 if (what)
690 errx_mutually_exclusive("--{add,delete,show,list,raw}");
691 what = ACT_SHOW;
692 break;
693
694 case 's':
695 if (what)
696 errx_mutually_exclusive("--{add,delete,show,list,raw}");
697 what = ACT_SHOW;
698 break;
699 case 't':
700 type = optarg;
701 break;
702 case 'v':
703 verbose = 1;
704 break;
705 case 'h':
706 usage(stdout);
707 case '?':
708 default:
709 usage(stderr);
710 }
711 }
712
713 /* -o <list> enables --show mode by default */
714 if (ncolumns && !what)
715 what = ACT_SHOW;
716
717 /* backwardly compatible default */
718 if (!what)
719 what = ACT_LIST;
720
721 /* --show default, could by modified by -o */
722 if (what == ACT_SHOW && !ncolumns) {
723 columns[ncolumns++] = COL_PARTNO;
724 columns[ncolumns++] = COL_START;
725 columns[ncolumns++] = COL_END;
726 columns[ncolumns++] = COL_SECTORS;
727 columns[ncolumns++] = COL_SIZE;
728 columns[ncolumns++] = COL_NAME;
729 columns[ncolumns++] = COL_UUID;
730 }
731
732 /*
733 * Note that 'partx /dev/sda1' == 'partx /dev/sda1 /dev/sda'
734 * so assume that the device and/or disk are always the last
735 * arguments to be passed to partx.
736 */
737 if (optind == argc - 2) {
738 /* passed 2 arguments:
739 * /dev/sda1 /dev/sda : partition + whole-disk
740 * -- /dev/sda1 : partition that should be used as a whole-disk
741 */
742 device = argv[optind];
743
744 if (strcmp(device, "-") == 0) {
745 device = NULL;
746 wholedisk = xstrdup(argv[optind + 1]);
747 } else {
748 device = argv[optind];
749 wholedisk = xstrdup(argv[optind + 1]);
750 }
751 } else if (optind == argc - 1) {
752 /* passed only one arg (ie: /dev/sda3 or /dev/sda) */
753 struct stat sb;
754
755 device = argv[optind];
756
757 if (stat(device, &sb))
758 err(EXIT_FAILURE, _("%s: stat failed"), device);
759
760 part_devno = sb.st_rdev;
761
762 if (blkid_devno_to_wholedisk(part_devno,
763 NULL, 0, &disk_devno) == 0 &&
764 part_devno != disk_devno)
765 wholedisk = blkid_devno_to_devname(disk_devno);
766
767 if (!wholedisk) {
768 wholedisk = xstrdup(device);
769 disk_devno = part_devno;
770 device = NULL;
771 part_devno = 0;
22853e4a 772 }
22853e4a 773 } else
c4ecaf21
DB
774 usage(stderr);
775
776 if (device && (upper || lower))
e22d8b95 777 errx(EXIT_FAILURE, _("--nr and <partition> are mutually exclusive"));
c4ecaf21
DB
778
779 assert(wholedisk);
780
781 if (device) {
782 /* use partno from given partition instead of --nr range, e.g:
783 * partx -d /dev/sda3
784 * is the same like:
785 * partx -d --nr 3 /dev/sda
786 */
787 struct stat sb;
788
789 if (!part_devno && !stat(device, &sb))
790 part_devno = sb.st_rdev;
791
792 lower = upper = get_partno_from_device(device, part_devno);
793 }
794
795 if (verbose)
796 printf("device: %s, whole-disk: %s, lower: %d, upper: %d\n",
797 device, wholedisk, lower, upper);
798
799 if (what == ACT_ADD || what == ACT_DELETE) {
800 struct stat x;
801
802 if (stat(wholedisk, &x) || !S_ISBLK(x.st_mode))
803 errx(EXIT_FAILURE, _("%s: not a block device"), wholedisk);
804 }
805 if ((fd = open(wholedisk, O_RDONLY)) == -1)
806 err(EXIT_FAILURE, _("%s: open failed"), wholedisk);
807
808 if (what == ACT_DELETE)
809 rc = del_parts(fd, wholedisk, disk_devno, lower, upper);
810 else {
811 blkid_probe pr = blkid_new_probe();
812 blkid_partlist ls = NULL;
813
814 if (!pr || blkid_probe_set_device(pr, fd, 0, 0))
815 warnx(_("%s: failed to initialize blkid prober"),
816 wholedisk);
817 else
818 ls = get_partlist(pr, wholedisk, type);
819
820 if (ls) {
821 int n = blkid_partlist_numof_partitions(ls);
822
823 if (lower < 0)
824 lower = n + lower + 1;
825 if (upper < 0)
826 upper = n + upper + 1;
827 if (lower > upper) {
828 warnx(_("defined range <%d:%d> "
829 "does not make sense"), lower, upper);
830 rc = -1, what = 0;
831 }
832
833 switch (what) {
834 case ACT_SHOW:
835 rc = show_parts(ls, tt_flags, lower, upper);
836 break;
837 case ACT_LIST:
838 rc = list_parts(ls, lower, upper);
839 break;
840 case ACT_ADD:
841 rc = add_parts(fd, wholedisk, ls, lower, upper);
842 break;
843 }
844 }
845 blkid_free_probe(pr);
846 }
847
848 close(fd);
849 return rc ? EXIT_FAILURE : EXIT_SUCCESS;
22853e4a 850}
c4ecaf21 851