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