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