2 * SPDX-License-Identifier: GPL-2.0-or-later
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
10 * partx: tell the kernel about your disk's partitions
11 * [This is not an fdisk - adding and removing partitions
12 * is not a change of the disk, but just telling the kernel
13 * about presence and numbering of on-disk partitions.]
15 * aeb, 2000-03-21 -- sah is 42 now
17 * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
18 * Rewritten to use libblkid for util-linux
19 * based on ideas from Karel Zak <kzak@redhat.com>
31 #include <libsmartcols.h>
34 #include "pathnames.h"
42 #include "closestream.h"
45 /* this is the default upper limit, could be modified by --nr */
46 #define SLICES_MAX 256
48 /* basic table settings */
51 PARTX_NOHEADINGS
= (1 << 1),
52 PARTX_EXPORT
= (1 << 2),
55 /* all the columns (-o option) */
69 #define ACT_ERROR "--{add,delete,show,list,raw,pairs}"
85 const char * const name
; /* header */
86 double whint
; /* width hint (N < 1 is in percent of termwidth) */
87 int flags
; /* SCOLS_FL_* */
91 /* columns descriptions */
92 static const struct colinfo infos
[] = {
93 [COL_PARTNO
] = { "NR", 0.25, SCOLS_FL_RIGHT
, N_("partition number") },
94 [COL_START
] = { "START", 0.30, SCOLS_FL_RIGHT
, N_("start of the partition in sectors") },
95 [COL_END
] = { "END", 0.30, SCOLS_FL_RIGHT
, N_("end of the partition in sectors") },
96 [COL_SECTORS
] = { "SECTORS", 0.30, SCOLS_FL_RIGHT
, N_("number of sectors") },
97 [COL_SIZE
] = { "SIZE", 0.30, SCOLS_FL_RIGHT
, N_("human readable size") },
98 [COL_NAME
] = { "NAME", 0.30, SCOLS_FL_TRUNC
, N_("partition name") },
99 [COL_UUID
] = { "UUID", 36, 0, N_("partition UUID")},
100 [COL_SCHEME
] = { "SCHEME", 0.1, SCOLS_FL_TRUNC
, N_("partition table type (dos, gpt, ...)")},
101 [COL_FLAGS
] = { "FLAGS", 0.1, SCOLS_FL_TRUNC
, N_("partition flags")},
102 [COL_TYPE
] = { "TYPE", 1, SCOLS_FL_RIGHT
, N_("partition type (a string, a UUID, or hex)")},
105 #define NCOLS ARRAY_SIZE(infos)
107 /* array with IDs of enabled columns */
108 static int columns
[NCOLS
];
109 static size_t ncolumns
;
112 static int partx_flags
;
113 static struct loopdev_cxt lc
;
116 static void assoc_loopdev(const char *fname
)
120 if (loopcxt_init(&lc
, 0))
121 err(EXIT_FAILURE
, _("failed to initialize loopcxt"));
123 rc
= loopcxt_find_unused(&lc
);
125 err(EXIT_FAILURE
, _("%s: failed to find unused loop device"),
129 printf(_("Trying to use '%s' for the loop device\n"),
130 loopcxt_get_device(&lc
));
132 if (loopcxt_set_backing_file(&lc
, fname
))
133 err(EXIT_FAILURE
, _("%s: failed to set backing file"), fname
);
135 rc
= loopcxt_setup_device(&lc
);
138 err(EXIT_FAILURE
, _("%s: failed to set up loop device"), fname
);
143 static inline int get_column_id(int num
)
145 assert(ARRAY_SIZE(columns
) == NCOLS
);
146 assert((size_t)num
< ncolumns
);
147 assert(columns
[num
] < (int) NCOLS
);
151 static inline const struct colinfo
*get_column_info(int num
)
153 return &infos
[ get_column_id(num
) ];
156 static int column_name_to_id(const char *name
, size_t namesz
)
162 for (i
= 0; i
< NCOLS
; i
++) {
163 const char *cn
= infos
[i
].name
;
165 if (!strncasecmp(name
, cn
, namesz
) && !*(cn
+ namesz
))
168 warnx(_("unknown column: %s"), name
);
173 * Given a partition return the corresponding partition number.
175 * Note that this function tries to use sysfs, otherwise it assumes that the
176 * last characters are always numeric (sda1, sdc20, etc).
178 static int get_partno_from_device(char *partition
, dev_t devno
)
182 char *p
, *end
= NULL
;
190 pc
= ul_new_sysfs_path(devno
, NULL
, NULL
);
194 rc
= ul_path_read_s32(pc
, &partno
, "partition");
201 sz
= strlen(partition
);
202 p
= partition
+ sz
- 1;
204 if (!isdigit((unsigned char) *p
))
207 while (isdigit((unsigned char) *(p
- 1))) p
--;
210 partno
= strtol(p
, &end
, 10);
211 if (errno
|| !end
|| *end
|| p
== end
)
216 errx(EXIT_FAILURE
, _("%s: failed to get partition number"), partition
);
219 static int get_max_partno(const char *disk
, dev_t devno
)
221 char path
[PATH_MAX
], *parent
, *dirname
= NULL
;
227 if (!devno
&& !stat(disk
, &st
))
231 parent
= strrchr(disk
, '/');
236 snprintf(path
, sizeof(path
), _PATH_SYS_DEVBLOCK
"/%d:%d/",
237 major(devno
), minor(devno
));
243 dirname
= xstrdup(path
);
245 while ((d
= readdir(dir
))) {
248 if (!strcmp(d
->d_name
, ".") ||
249 !strcmp(d
->d_name
, ".."))
251 #ifdef _DIRENT_HAVE_D_TYPE
252 if (d
->d_type
!= DT_DIR
&& d
->d_type
!= DT_UNKNOWN
)
255 if (strncmp(parent
, d
->d_name
, strlen(parent
)) != 0)
257 snprintf(path
, sizeof(path
), "%s/partition", d
->d_name
);
259 fd
= openat(dirfd(dir
), path
, O_RDONLY
);
262 FILE *f
= fdopen(fd
, "r");
264 if (fscanf(f
, "%d", &x
) == 1 && x
> partno
)
278 static int recount_range_by_pt(blkid_partlist ls
, int *lower
, int *upper
)
280 int n
= 0, i
, nparts
= blkid_partlist_numof_partitions(ls
);
282 for (i
= 0; i
< nparts
; i
++) {
283 blkid_partition par
= blkid_partlist_get_partition(ls
, i
);
284 int partno
= blkid_partition_get_partno(par
);
289 *lower
= n
+ *lower
+ 1;
291 *upper
= n
+ *upper
+ 1;
293 if (*lower
> *upper
&& *upper
!= 0) {
294 warnx(_("specified range <%d:%d> does not make sense"), *lower
, *upper
);
298 printf(_("range recount: max partno=%d, lower=%d, upper=%d\n"), n
, *lower
, *upper
);
302 static void del_parts_warnx(const char *device
, int first
, int last
)
305 warnx(_("%s: error deleting partition %d"), device
, first
);
307 warnx(_("%s: error deleting partitions %d-%d"),
308 device
, first
, last
);
311 static int del_parts(int fd
, const char *device
, dev_t devno
,
312 int lower
, int upper
)
314 int rc
= 0, i
, errfirst
= 0, errlast
= 0;
319 /* recount range by information in /sys */
322 if (!upper
|| lower
< 0 || upper
< 0) {
323 int n
= get_max_partno(device
, devno
);
327 upper
= n
+ upper
+ 1;
329 lower
= n
+ lower
+ 1;
332 warnx(_("specified range <%d:%d> "
333 "does not make sense"), lower
, upper
);
337 for (i
= lower
; i
<= upper
; i
++) {
338 if (partx_del_partition(fd
, i
) == 0) {
340 printf(_("%s: partition #%d removed\n"), device
, i
);
344 if (errno
== ENXIO
) {
346 printf(_("%s: partition #%d doesn't exist\n"), device
, i
);
351 warn(_("%s: deleting partition #%d failed"), device
, i
);
353 errlast
= errfirst
= i
;
354 else if (errlast
+ 1 == i
)
357 del_parts_warnx(device
, errfirst
, errlast
);
358 errlast
= errfirst
= i
;
363 del_parts_warnx(device
, errfirst
, errlast
);
368 static void add_parts_warnx(const char *device
, int first
, int last
)
371 warnx(_("%s: error adding partition %d"), device
, first
);
373 warnx(_("%s: error adding partitions %d-%d"),
374 device
, first
, last
);
377 static int add_parts(int fd
, const char *device
,
378 blkid_partlist ls
, int lower
, int upper
)
380 int i
, nparts
, rc
, errfirst
= 0, errlast
= 0;
386 rc
= recount_range_by_pt(ls
, &lower
, &upper
);
390 nparts
= blkid_partlist_numof_partitions(ls
);
392 for (i
= 0; i
< nparts
; i
++) {
393 blkid_partition par
= blkid_partlist_get_partition(ls
, i
);
394 int n
= blkid_partition_get_partno(par
);
395 uintmax_t start
, size
;
397 if (lower
&& n
< lower
)
399 if (upper
&& n
> upper
)
402 start
= blkid_partition_get_start(par
);
403 size
= blkid_partition_get_size(par
);
405 if (blkid_partition_is_extended(par
))
407 * Let's follow the Linux kernel and reduce
408 * DOS extended partition to 1 or 2 sectors.
410 size
= min(size
, (uintmax_t) 2);
412 if (partx_add_partition(fd
, n
, start
, size
) == 0) {
414 printf(_("%s: partition #%d added\n"), device
, n
);
419 warn(_("%s: adding partition #%d failed"), device
, n
);
421 errlast
= errfirst
= n
;
422 else if (errlast
+ 1 == n
)
425 add_parts_warnx(device
, errfirst
, errlast
);
426 errlast
= errfirst
= n
;
431 add_parts_warnx(device
, errfirst
, errlast
);
434 * The kernel with enabled partitions scanner for loop devices add *all*
435 * partitions, so we should delete any extra, unwanted ones, when the -n
438 if (loopdev
&& loopcxt_is_partscan(&lc
) && (lower
|| upper
)) {
439 for (i
= 0; i
< nparts
; i
++) {
440 blkid_partition par
= blkid_partlist_get_partition(ls
, i
);
441 int n
= blkid_partition_get_partno(par
);
443 if (n
< lower
|| n
> upper
)
444 partx_del_partition(fd
, n
);
451 static void upd_parts_warnx(const char *device
, int first
, int last
)
454 warnx(_("%s: error updating partition %d"), device
, first
);
456 warnx(_("%s: error updating partitions %d-%d"),
457 device
, first
, last
);
460 static int upd_parts(int fd
, const char *device
, dev_t devno
,
461 blkid_partlist ls
, int lower
, int upper
)
463 int n
, nparts
, rc
= 0, errfirst
= 0, errlast
= 0, err
;
465 uintmax_t start
, size
;
471 /* recount range by information in /sys, if on disk number of
472 * partitions is greater than in /sys the use on-disk limit */
473 nparts
= blkid_partlist_numof_partitions(ls
);
476 if (!upper
|| lower
< 0 || upper
< 0) {
477 n
= get_max_partno(device
, devno
);
479 upper
= n
> nparts
? n
: nparts
;
481 upper
= n
+ upper
+ 1;
483 lower
= n
+ lower
+ 1;
486 warnx(_("specified range <%d:%d> "
487 "does not make sense"), lower
, upper
);
491 for (n
= lower
; n
<= upper
; n
++) {
492 par
= blkid_partlist_get_partition_by_partno(ls
, n
);
495 warn(_("%s: no partition #%d"), device
, n
);
499 start
= blkid_partition_get_start(par
);
500 size
= blkid_partition_get_size(par
);
501 if (blkid_partition_is_extended(par
))
503 * Let's follow the Linux kernel and reduce
504 * DOS extended partition to 1 or 2 sectors.
506 size
= min(size
, (uintmax_t) 2);
508 err
= partx_del_partition(fd
, n
);
509 if (err
== -1 && errno
== ENXIO
)
510 err
= 0; /* good, it already doesn't exist */
511 if (err
== -1 && errno
== EBUSY
)
514 err
= partx_resize_partition(fd
, n
, start
, size
);
516 printf(_("%s: partition #%d resized\n"), device
, n
);
520 if (err
== 0 && partx_add_partition(fd
, n
, start
, size
) == 0) {
522 printf(_("%s: partition #%d added\n"), device
, n
);
530 warn(_("%s: updating partition #%d failed"), device
, n
);
532 errlast
= errfirst
= n
;
533 else if (errlast
+ 1 == n
)
536 upd_parts_warnx(device
, errfirst
, errlast
);
537 errlast
= errfirst
= n
;
542 upd_parts_warnx(device
, errfirst
, errlast
);
546 static int list_parts(blkid_partlist ls
, int lower
, int upper
)
552 rc
= recount_range_by_pt(ls
, &lower
, &upper
);
556 nparts
= blkid_partlist_numof_partitions(ls
);
558 for (i
= 0; i
< nparts
; i
++) {
559 blkid_partition par
= blkid_partlist_get_partition(ls
, i
);
560 int n
= blkid_partition_get_partno(par
);
561 uintmax_t start
, size
;
563 if (lower
&& n
< lower
)
565 if (upper
&& n
> upper
)
568 start
= blkid_partition_get_start(par
);
569 size
= blkid_partition_get_size(par
);
571 printf(P_("#%2d: %9ju-%9ju (%9ju sector, %6ju MB)\n",
572 "#%2d: %9ju-%9ju (%9ju sectors, %6ju MB)\n",
574 n
, start
, start
+ size
-1,
575 size
, (size
<< 9) / 1000000);
580 static int add_scols_line(struct libscols_table
*table
, blkid_partition par
)
582 struct libscols_line
*line
;
588 line
= scols_table_new_line(table
, NULL
);
590 warn(_("failed to allocate output line"));
594 for (i
= 0; (size_t)i
< ncolumns
; i
++) {
595 char *str
= NULL
; /* allocated string */
596 const char *cstr
= NULL
; /* foreign string */
598 switch (get_column_id(i
)) {
600 xasprintf(&str
, "%d", blkid_partition_get_partno(par
));
603 xasprintf(&str
, "%ju", blkid_partition_get_start(par
));
606 xasprintf(&str
, "%ju",
607 blkid_partition_get_start(par
) +
608 blkid_partition_get_size(par
) - 1);
611 xasprintf(&str
, "%ju", blkid_partition_get_size(par
));
614 if (partx_flags
& FL_BYTES
)
615 xasprintf(&str
, "%ju", (uintmax_t)
616 blkid_partition_get_size(par
) << 9);
618 str
= size_to_human_string(SIZE_SUFFIX_1LETTER
,
619 blkid_partition_get_size(par
) << 9);
622 cstr
= blkid_partition_get_name(par
);
625 cstr
= blkid_partition_get_uuid(par
);
628 if (blkid_partition_get_type_string(par
))
629 cstr
= blkid_partition_get_type_string(par
);
631 xasprintf(&str
, "0x%x",
632 blkid_partition_get_type(par
));
635 xasprintf(&str
, "0x%llx", blkid_partition_get_flags(par
));
639 blkid_parttable tab
= blkid_partition_get_table(par
);
641 cstr
= blkid_parttable_get_type(tab
);
649 rc
= scols_line_set_data(line
, i
, cstr
);
651 rc
= scols_line_refer_data(line
, i
, str
);
653 warn(_("failed to add output data"));
661 static int show_parts(blkid_partlist ls
, int scols_flags
, int lower
, int upper
)
664 struct libscols_table
*table
;
669 nparts
= blkid_partlist_numof_partitions(ls
);
674 table
= scols_new_table();
676 warn(_("failed to allocate output table"));
679 scols_table_enable_raw(table
, !!(scols_flags
& PARTX_RAW
));
680 scols_table_enable_export(table
, !!(scols_flags
& PARTX_EXPORT
));
681 scols_table_enable_noheadings(table
, !!(scols_flags
& PARTX_NOHEADINGS
));
683 for (i
= 0; (size_t)i
< ncolumns
; i
++) {
684 const struct colinfo
*col
= get_column_info(i
);
686 if (!scols_table_new_column(table
, col
->name
, col
->whint
, col
->flags
)) {
687 warnx(_("failed to allocate output column"));
692 rc
= recount_range_by_pt(ls
, &lower
, &upper
);
696 for (i
= 0; i
< nparts
; i
++) {
697 blkid_partition par
= blkid_partlist_get_partition(ls
, i
);
698 int n
= blkid_partition_get_partno(par
);
700 if (lower
&& n
< lower
)
702 if (upper
&& n
> upper
)
705 rc
= add_scols_line(table
, par
);
711 scols_print_table(table
);
713 scols_unref_table(table
);
717 static blkid_partlist
get_partlist(blkid_probe pr
,
718 const char *device
, char *type
)
727 char *name
[] = { type
, NULL
};
729 if (blkid_probe_filter_partitions_type(pr
,
730 BLKID_FLTR_ONLYIN
, name
)) {
731 warnx(_("failed to initialize blkid "
732 "filter for '%s'"), type
);
737 ls
= blkid_probe_get_partitions(pr
);
739 warnx(_("%s: failed to read partition table"), device
);
743 tab
= blkid_partlist_get_table(ls
);
744 if (verbose
&& tab
) {
745 printf(_("%s: partition table type '%s' detected\n"),
746 device
, blkid_parttable_get_type(tab
));
748 if (!blkid_partlist_numof_partitions(ls
))
749 printf(_("%s: partition table with no partitions"), device
);
755 static void __attribute__((__noreturn__
)) usage(void)
760 fputs(USAGE_HEADER
, out
);
762 _(" %s [-a|-d|-s|-u] [--nr <n:m> | <partition>] <disk>\n"),
763 program_invocation_short_name
);
765 fputs(USAGE_SEPARATOR
, out
);
766 fputs(_("Tell the kernel about the presence and numbering of partitions.\n"), out
);
768 fputs(USAGE_OPTIONS
, out
);
769 fputs(_(" -a, --add add specified partitions or all of them\n"), out
);
770 fputs(_(" -d, --delete delete specified partitions or all of them\n"), out
);
771 fputs(_(" -u, --update update specified partitions or all of them\n"), out
);
772 fputs(_(" -s, --show list partitions\n\n"), out
);
773 fputs(_(" -b, --bytes print SIZE in bytes rather than in human readable format\n"), out
);
774 fputs(_(" -g, --noheadings don't print headings for --show\n"), out
);
775 fputs(_(" -n, --nr <n:m> specify the range of partitions (e.g. --nr 2:4)\n"), out
);
776 fputs(_(" -o, --output <list> define which output columns to use\n"), out
);
777 fputs(_(" --output-all output all columns\n"), out
);
778 fputs(_(" -P, --pairs use key=\"value\" output format\n"), out
);
779 fputs(_(" -r, --raw use raw output format\n"), out
);
780 fputs(_(" -S, --sector-size <num> overwrite sector size\n"), out
);
781 fputs(_(" -t, --type <type> specify the partition type\n"), out
);
782 fputs(_(" --list-types list supported partition types and exit\n"), out
);
783 fputs(_(" -v, --verbose verbose mode\n"), out
);
785 fputs(USAGE_SEPARATOR
, out
);
786 fprintf(out
, USAGE_HELP_OPTIONS(22));
788 fputs(USAGE_COLUMNS
, out
);
789 for (i
= 0; i
< NCOLS
; i
++)
790 fprintf(out
, " %10s %s\n", infos
[i
].name
, _(infos
[i
].help
));
792 fprintf(out
, USAGE_MAN_TAIL("partx(8)"));
797 int main(int argc
, char **argv
)
799 int fd
, c
, what
= ACT_NONE
, lower
= 0, upper
= 0, rc
= 0;
802 char *device
= NULL
; /* pointer to argv[], ie: /dev/sda1 */
803 char *wholedisk
= NULL
; /* allocated, ie: /dev/sda */
805 dev_t disk_devno
= 0, part_devno
= 0;
806 unsigned int sector_size
= 0;
809 OPT_LIST_TYPES
= CHAR_MAX
+ 1,
812 static const struct option long_opts
[] = {
813 { "bytes", no_argument
, NULL
, 'b' },
814 { "noheadings", no_argument
, NULL
, 'g' },
815 { "raw", no_argument
, NULL
, 'r' },
816 { "list", no_argument
, NULL
, 'l' },
817 { "show", no_argument
, NULL
, 's' },
818 { "add", no_argument
, NULL
, 'a' },
819 { "delete", no_argument
, NULL
, 'd' },
820 { "update", no_argument
, NULL
, 'u' },
821 { "type", required_argument
, NULL
, 't' },
822 { "list-types", no_argument
, NULL
, OPT_LIST_TYPES
},
823 { "nr", required_argument
, NULL
, 'n' },
824 { "output", required_argument
, NULL
, 'o' },
825 { "output-all", no_argument
, NULL
, OPT_OUTPUT_ALL
},
826 { "pairs", no_argument
, NULL
, 'P' },
827 { "sector-size",required_argument
, NULL
, 'S' },
828 { "help", no_argument
, NULL
, 'h' },
829 { "version", no_argument
, NULL
, 'V' },
830 { "verbose", no_argument
, NULL
, 'v' },
834 static const ul_excl_t excl
[] = { /* rows and cols in ASCII order */
835 { 'P','a','d','l','r','s','u' },
838 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
840 setlocale(LC_ALL
, "");
841 bindtextdomain(PACKAGE
, LOCALEDIR
);
843 close_stdout_atexit();
845 while ((c
= getopt_long(argc
, argv
,
846 "abdglrsuvn:t:o:PS:hV", long_opts
, NULL
)) != -1) {
848 err_exclusive_options(c
, long_opts
, excl
, excl_st
);
855 partx_flags
|= FL_BYTES
;
861 scols_flags
|= PARTX_NOHEADINGS
;
867 if (parse_range(optarg
, &lower
, &upper
, 0))
868 errx(EXIT_FAILURE
, _("failed to parse --nr <M-N> range"));
874 for (ncolumns
= 0; ncolumns
< ARRAY_SIZE(infos
); ncolumns
++)
875 columns
[ncolumns
] = ncolumns
;
878 scols_flags
|= PARTX_EXPORT
;
882 scols_flags
|= PARTX_RAW
;
889 sector_size
= strtou32_or_err(optarg
, _("invalid sector size argument"));
903 const char *name
= NULL
;
905 while (blkid_partitions_get_name(idx
++, &name
) == 0)
912 print_version(EXIT_SUCCESS
);
914 errtryhelp(EXIT_FAILURE
);
918 if (what
== ACT_NONE
)
921 /* --show default, could by modified by -o */
922 if (what
== ACT_SHOW
&& !ncolumns
) {
923 columns
[ncolumns
++] = COL_PARTNO
;
924 columns
[ncolumns
++] = COL_START
;
925 columns
[ncolumns
++] = COL_END
;
926 columns
[ncolumns
++] = COL_SECTORS
;
927 columns
[ncolumns
++] = COL_SIZE
;
928 columns
[ncolumns
++] = COL_NAME
;
929 columns
[ncolumns
++] = COL_UUID
;
932 if (what
== ACT_SHOW
&& outarg
&&
933 string_add_to_idarray(outarg
, columns
, ARRAY_SIZE(columns
),
934 &ncolumns
, column_name_to_id
) < 0)
938 * Note that 'partx /dev/sda1' == 'partx /dev/sda1 /dev/sda'
939 * so assume that the device and/or disk are always the last
940 * arguments to be passed to partx.
942 if (optind
== argc
- 2) {
943 /* passed 2 arguments:
944 * /dev/sda1 /dev/sda : partition + whole-disk
945 * -- /dev/sda1 : partition that should be used as a whole-disk
947 device
= argv
[optind
];
949 if (strcmp(device
, "-") == 0) {
951 wholedisk
= xstrdup(argv
[optind
+ 1]);
953 device
= argv
[optind
];
954 wholedisk
= xstrdup(argv
[optind
+ 1]);
956 if (device
&& wholedisk
&& !startswith(device
, wholedisk
))
957 errx(EXIT_FAILURE
, _("partition and disk name do not match"));
959 } else if (optind
== argc
- 1) {
960 /* passed only one arg (ie: /dev/sda3 or /dev/sda) */
963 device
= argv
[optind
];
965 if (stat(device
, &sb
))
966 err(EXIT_FAILURE
, _("stat of %s failed"), device
);
968 part_devno
= sb
.st_rdev
;
970 if (blkid_devno_to_wholedisk(part_devno
,
971 NULL
, 0, &disk_devno
) == 0 &&
972 part_devno
!= disk_devno
)
973 wholedisk
= blkid_devno_to_devname(disk_devno
);
976 wholedisk
= xstrdup(device
);
977 disk_devno
= part_devno
;
982 warnx(_("bad usage"));
983 errtryhelp(EXIT_FAILURE
);
985 if (device
&& (upper
|| lower
))
986 errx(EXIT_FAILURE
, _("--nr and <partition> are mutually exclusive"));
991 /* use partno from given partition instead of --nr range, e.g:
994 * partx -d --nr 3 /dev/sda
998 if (!part_devno
&& !stat(device
, &sb
))
999 part_devno
= sb
.st_rdev
;
1001 lower
= upper
= get_partno_from_device(device
, part_devno
);
1005 printf(_("partition: %s, disk: %s, lower: %d, upper: %d\n"),
1006 device
? device
: "none", wholedisk
, lower
, upper
);
1008 if (what
== ACT_ADD
|| what
== ACT_DELETE
) {
1011 if (stat(wholedisk
, &x
))
1012 errx(EXIT_FAILURE
, "%s", wholedisk
);
1014 if (S_ISREG(x
.st_mode
)) {
1015 /* not a blkdev, try to associate it to a loop device */
1016 if (what
== ACT_DELETE
)
1017 errx(EXIT_FAILURE
, _("%s: cannot delete partitions"),
1019 if (!loopmod_supports_partscan())
1020 errx(EXIT_FAILURE
, _("%s: partitioned loop devices unsupported"),
1022 assoc_loopdev(wholedisk
);
1024 wholedisk
= xstrdup(lc
.device
);
1025 } else if (!S_ISBLK(x
.st_mode
))
1026 errx(EXIT_FAILURE
, _("%s: not a block device"), wholedisk
);
1028 if ((fd
= open(wholedisk
, O_RDONLY
)) == -1)
1029 err(EXIT_FAILURE
, _("cannot open %s"), wholedisk
);
1031 if (what
== ACT_DELETE
)
1032 rc
= del_parts(fd
, wholedisk
, disk_devno
, lower
, upper
);
1034 blkid_probe pr
= blkid_new_probe();
1035 blkid_partlist ls
= NULL
;
1037 if (!pr
|| blkid_probe_set_device(pr
, fd
, 0, 0))
1038 warnx(_("%s: failed to initialize blkid prober"),
1042 blkid_probe_set_sectorsize(pr
, sector_size
);
1044 ls
= get_partlist(pr
, wholedisk
, type
);
1050 rc
= show_parts(ls
, scols_flags
, lower
, upper
);
1053 rc
= list_parts(ls
, lower
, upper
);
1056 rc
= add_parts(fd
, wholedisk
, ls
, lower
, upper
);
1059 rc
= upd_parts(fd
, wholedisk
, disk_devno
, ls
, lower
, upper
);
1069 blkid_free_probe(pr
);
1075 loopcxt_deinit(&lc
);
1077 if (close_fd(fd
) != 0)
1078 err(EXIT_FAILURE
, _("write failed"));
1080 return rc
? EXIT_FAILURE
: EXIT_SUCCESS
;