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