summaryrefslogtreecommitdiffstats
path: root/partx/partx.c
diff options
context:
space:
mode:
authorDavidlohr Bueso2010-12-09 21:54:17 +0100
committerKarel Zak2010-12-09 21:54:17 +0100
commitc4ecaf21d59671ac7ec0bd26bd2c346c98c7771c (patch)
treecd89a4e8048653d693b7d9f4a1507479d1ad7314 /partx/partx.c
parentmount: be more explicit about --move in mount.8 (diff)
downloadkernel-qcow2-util-linux-c4ecaf21d59671ac7ec0bd26bd2c346c98c7771c.tar.gz
kernel-qcow2-util-linux-c4ecaf21d59671ac7ec0bd26bd2c346c98c7771c.tar.xz
kernel-qcow2-util-linux-c4ecaf21d59671ac7ec0bd26bd2c346c98c7771c.zip
partx: complete rewrite
Co-Author: Karel Zak <kzak@redhat.com> Signed-off-by: Davidlohr Bueso <dave@gnu.org> Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'partx/partx.c')
-rw-r--r--partx/partx.c1082
1 files changed, 756 insertions, 326 deletions
diff --git a/partx/partx.c b/partx/partx.c
index aa5a2ad8f..e0f1f2a9b 100644
--- a/partx/partx.c
+++ b/partx/partx.c
@@ -1,404 +1,834 @@
/*
- * Given a block device and a partition table type,
- * try to parse the partition table, and list the
- * contents. Optionally add or remove partitions.
- *
+ * partx: tell the kernel about your disk's partitions
* [This is not an fdisk - adding and removing partitions
* is not a change of the disk, but just telling the kernel
* about presence and numbering of on-disk partitions.]
*
- * Call:
- * partx [-{l|a|d}] [--type TYPE] [--nr M-N] [partition] wholedisk
- * where TYPE is {dos|bsd|solaris|unixware|gpt}.
- *
- * Read wholedisk and add all partitions:
- * partx -a wholedisk
- *
- * Subdivide a partition into slices (and delete or shrink the partition):
- * [Not easy: one needs the partition number of partition -
- * that is the last 4 or 6 bits of the minor; it can also be found
- * in /proc/partitions; but there is no good direct way.]
- * partx -a partition wholedisk
- *
- * Delete all partitions from wholedisk:
- * partx -d wholedisk
- *
- * Delete partitions M-N from wholedisk:
- * partx -d --nr M-N wholedisk
- *
* aeb, 2000-03-21 -- sah is 42 now
+ *
+ * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
+ * Rewritten to use libblkid for util-linux-ng
+ * based on ideas from Karel Zak <kzak@redhat.com>
*/
#include <stdio.h>
#include <fcntl.h>
+#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
+#include <assert.h>
#include <sys/ioctl.h>
-#include <linux/hdreg.h> /* HDIO_GETGEO */
-#ifdef HAVE_LINUX_COMPILER_H
-#include <linux/compiler.h>
-#endif
#include <linux/blkpg.h>
+#include <dirent.h>
+
+#include <blkid.h>
#include "c.h"
+#include "pathnames.h"
+#include "nls.h"
+#include "tt.h"
#include "blkdev.h"
-
+#include "strutils.h"
+#include "xalloc.h"
#include "partx.h"
-#include "crc32.h"
-static void errmerge(int err, int m, char *msg1, char *msg2);
-#define MAXTYPES 64
-#define MAXSLICES 256
+/* this is the default upper limit, could be modified by --nr */
+#define SLICES_MAX 256
+
+/* all the columns (-o option) */
+enum {
+ COL_PARTNO,
+ COL_START,
+ COL_END,
+ COL_SECTORS,
+ COL_SIZE,
+ COL_NAME,
+ COL_UUID,
+ COL_TYPE,
+ __NCOLUMNS
+};
-struct slice slices[MAXSLICES];
+enum {
+ ACT_LIST = 1,
+ ACT_SHOW,
+ ACT_ADD,
+ ACT_DELETE
+};
+
+enum {
+ FL_BYTES = (1 << 1)
+};
+
+/* column names */
+struct colinfo {
+ const char *name; /* header */
+ double whint; /* width hint (N < 1 is in percent of termwidth) */
+ int flags; /* TT_FL_* */
+ const char *help;
+};
-enum action { LIST, ADD, DELETE };
+/* columns descriptions */
+struct colinfo infos[__NCOLUMNS] = {
+ [COL_PARTNO] = { "PART", 0.25, TT_FL_RIGHT, N_("partition number") },
+ [COL_START] = { "START", 0.30, TT_FL_RIGHT, N_("start of the partition in sectors") },
+ [COL_END] = { "END", 0.30, TT_FL_RIGHT, N_("end of the partition in sectors") },
+ [COL_SECTORS] = { "SECTORS", 0.30, TT_FL_RIGHT, N_("number of sectors") },
+ [COL_SIZE] = { "SIZE", 0.30, TT_FL_RIGHT, N_("human readable size") },
+ [COL_NAME] = { "NAME", 0.30, TT_FL_TRUNC, N_("partition name") },
+ [COL_UUID] = { "UUID", 36, 0, N_("partition UUID")},
+ [COL_TYPE] = { "TYPE", 1, TT_FL_RIGHT, N_("partition type; Extended, Primary or Logical")},
+};
+/* array with IDs of enabled columns */
+static int columns[__NCOLUMNS], ncolumns;
+
+static int verbose;
+static int partx_flags;
-struct pt {
- char *type;
- ptreader *fn;
-} pts[MAXTYPES];
-int ptct;
-static void
-addpts(char *t, ptreader f)
+static inline int get_column_id(int num)
{
- if (ptct >= MAXTYPES) {
- fprintf(stderr, "addpts: too many types\n");
- exit(1);
- }
- pts[ptct].type = t;
- pts[ptct].fn = f;
- ptct++;
+ assert(ARRAY_SIZE(columns) == __NCOLUMNS);
+ assert(num < ncolumns);
+ assert(columns[num] < __NCOLUMNS);
+ return columns[num];
}
-static void
-initpts(void)
+static inline struct colinfo *get_column_info(int num)
{
- addpts("gpt", read_gpt_pt);
- addpts("dos", read_dos_pt);
- addpts("bsd", read_bsd_pt);
- addpts("solaris", read_solaris_pt);
- addpts("unixware", read_unixware_pt);
- addpts("sun", read_sun_pt);
- addpts("mac", read_mac_pt);
+ return &infos[ get_column_id(num) ];
}
-static char short_opts[] = "ladgvn:t:";
-static const struct option long_opts[] = {
- { "gpt", no_argument, NULL, 'g' },
- { "type", required_argument, NULL, 't' },
- { "nr", required_argument, NULL, 'n' },
- { NULL, 0, NULL, 0 }
-};
+static int column_name_to_id(const char *name, size_t namesz)
+{
+ int i;
-/* Used in gpt.c */
-int force_gpt=0;
-
-int
-main(int argc, char **argv){
- int fd, fd2, c, i, j, k, n;
- unsigned long long size;
- struct hd_geometry g;
- struct slice all;
- struct blkpg_ioctl_arg a;
- struct blkpg_partition pt;
- struct pt *ptp;
- enum action what = LIST;
- char *p, *type, *diskdevice, *device;
- int lower, upper;
- int verbose = 0;
- int ret = 0;
-
- initpts();
- init_crc32();
-
- lower = upper = 0;
- type = device = diskdevice = NULL;
-
- while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL))
- != -1) switch(c) {
- case 'l':
- what = LIST; break;
- case 'a':
- what = ADD; break;
- case 'd':
- what = DELETE; break;
- case 'g':
- force_gpt = 1; break;
- case 'n':
- p = optarg;
- lower = atoi(p);
- p = strchr(p, '-');
- if (p)
- upper = atoi(p+1);
- else
- upper = lower;
- break;
- case 't':
- type = optarg;
- break;
- case 'v':
- verbose = 1;
- break;
- case '?':
- default:
- fprintf(stderr, "unknown option\n");
- exit(1);
- }
+ assert(name);
- if (optind == argc-2) {
- device = argv[optind];
- diskdevice = argv[optind+1];
- } else if (optind == argc-1) {
- diskdevice = device = argv[optind];
- } else {
- fprintf(stderr, "call: partx -opts [device] wholedisk\n");
- exit(1);
- }
+ for (i = 0; i < __NCOLUMNS; i++) {
+ const char *cn = infos[i].name;
- fd = open(diskdevice, O_RDONLY);
- if (fd == -1) {
- perror(diskdevice);
- exit(1);
+ if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
+ return i;
}
+ warnx(_("unknown column: %s"), name);
+ return -1;
+}
- /* remove the indicated partitions from the kernel partition tables */
- if (what == DELETE) {
- if (device != diskdevice) {
- fprintf(stderr,
- "call: partx -d [--nr M-N] wholedisk\n");
- exit(1);
+/*
+ * Given a partition return the corresponding partition number.
+ *
+ * Note that this function tries to use sysfs, otherwise it assumes that the
+ * last characters are always numeric (sda1, sdc20, etc).
+ *
+ * Returns -1 on error.
+ */
+static int get_partno_from_device(char *partition, dev_t devno)
+{
+ int partno = 0;
+ size_t sz;
+ char *p, *end = NULL;
+
+ assert(partition);
+
+ if (devno) {
+ /* the device exits, read the partition number from /sys
+ * TODO: move this to stuff to lib/sysfs.c */
+ char path[PATH_MAX];
+ FILE *f;
+
+ snprintf(path, sizeof(path),
+ _PATH_SYS_DEVBLOCK "/%d:%d/partition",
+ major(devno), minor(devno));
+ f = fopen(path, "r");
+ if (f) {
+ if (fscanf(f, "%d", &partno) != 1)
+ partno = 0;
+ fclose(f);
}
+ if (partno)
+ return partno;
+ }
- if (!lower)
- lower = 1;
+ sz = strlen(partition);
+ p = partition + sz - 1;
- while (upper == 0 || lower <= upper) {
- int err;
+ if (!isdigit((unsigned int) *p))
+ goto err;
- if (lower > MAXSLICES)
- break;
- pt.pno = lower;
- pt.start = 0;
- pt.length = 0;
- pt.devname[0] = 0;
- pt.volname[0] = 0;
- a.op = BLKPG_DEL_PARTITION;
- a.flags = 0;
- a.datalen = sizeof(pt);
- a.data = &pt;
- if (ioctl(fd, BLKPG, &a) == -1)
- err = errno;
- else
- err = 0;
- errmerge(err, lower,
- "error deleting partition %d: ",
- "error deleting partitions %d-%d: ");
- /* expected errors:
- EBUSY: mounted or in use as swap
- ENXIO: no such nonempty partition
- EINVAL: not wholedisk, or bad pno
- EACCES/EPERM: permission denied
- */
- if (err && err != EBUSY && err != ENXIO) {
- ret = 1;
- break;
+ while (isdigit((unsigned int) *(p - 1))) p--;
+
+ errno = 0;
+ partno = strtol(p, &end, 10);
+ if (errno || !end || *end || p == end)
+ goto err;
+
+ return partno;
+err:
+ errx(EXIT_FAILURE, _("%s: failed to get partition number"), partition);
+}
+
+static int get_max_partno(const char *disk, dev_t devno)
+{
+ char path[PATH_MAX], *parent;
+ struct stat st;
+ DIR *dir;
+ struct dirent *d;
+ int partno = 0;
+
+ if (!devno && !stat(disk, &st))
+ devno = st.st_rdev;
+ if (!devno)
+ goto dflt;
+ parent = strrchr(disk, '/');
+ if (!parent)
+ goto dflt;
+ parent++;
+
+ snprintf(path, sizeof(path), _PATH_SYS_DEVBLOCK "/%d:%d/",
+ major(devno), minor(devno));
+
+ dir = opendir(path);
+ if (!dir)
+ goto dflt;
+
+ while ((d = readdir(dir))) {
+ int fd;
+
+ if (!strcmp(d->d_name, ".") ||
+ !strcmp(d->d_name, ".."))
+ continue;
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (d->d_type != DT_DIR)
+ continue;
+#endif
+ if (strncmp(parent, d->d_name, strlen(parent)))
+ continue;
+ snprintf(path, sizeof(path), "%s/partition", d->d_name);
+
+ fd = openat(dirfd(dir), path, O_RDONLY);
+ if (fd) {
+ int x = 0;
+ FILE *f = fdopen(fd, "r");
+ if (f) {
+ if (fscanf(f, "%d", &x) == 1 && x > partno)
+ partno = x;
+ fclose(f);
}
- if (err == 0 && verbose)
- printf("deleted partition %d\n", lower);
- lower++;
}
- errmerge(0, 0,
- "error deleting partition %d: ",
- "error deleting partitions %d-%d: ");
- return ret;
}
- if (device != diskdevice) {
- fd2 = open(device, O_RDONLY);
- if (fd2 == -1) {
- perror(device);
- exit(1);
+ closedir(dir);
+ return partno;
+dflt:
+ return SLICES_MAX;
+}
+
+static void del_parts_warnx(const char *device, int first, int last)
+{
+ if (first == last)
+ warnx(_("%s: error deleting partition %d"), device, first);
+ else
+ warnx(_("%s: error deleting partitions %d-%d"),
+ device, first, last);
+}
+
+static int del_parts(int fd, const char *device, dev_t devno,
+ int lower, int upper)
+{
+ int rc = 0, i, errfirst = 0, errlast = 0;
+
+ assert(fd >= 0);
+ assert(device);
+
+ if (!lower)
+ lower = 1;
+ if (!upper || lower < 0 || upper < 0) {
+ int n = get_max_partno(device, devno);
+ if (!upper)
+ upper = n;
+ else if (upper < 0)
+ upper = n + upper + 1;
+ if (lower < 0)
+ lower = n + lower + 1;
+ }
+ if (lower > upper) {
+ warnx(_("defined range <%d:%d> "
+ "does not make sense"), lower, upper);
+ return -1;
+ }
+
+ for (i = lower; i <= upper; i++) {
+ if (partx_del_partition(fd, i) == 0) {
+ if (verbose)
+ printf(_("%s: partition #%d removed\n"), device, i);
+ continue;
+ }
+ rc = -1;
+ if (verbose)
+ warn(_("%s: delete partition #%d failed"), device, i);
+ if (!errfirst)
+ errlast = errfirst = i;
+ else if (errlast + 1 == i)
+ errlast++;
+ else {
+ del_parts_warnx(device, errfirst, errlast);
+ errlast = errfirst = i;
}
- } else {
- fd2 = fd;
}
- if (ioctl(fd, HDIO_GETGEO, &g)) {
- perror("HDIO_GETGEO");
- exit(1);
+ if (errfirst)
+ del_parts_warnx(device, errfirst, errlast);
+ return rc;
+}
+
+static void add_parts_warnx(const char *device, int first, int last)
+{
+ if (first == last)
+ warnx(_("%s: error adding partition %d"), device, first);
+ else
+ warnx(_("%s: error adding partitions %d-%d"),
+ device, first, last);
+}
+
+static int add_parts(int fd, const char *device,
+ blkid_partlist ls, int lower, int upper)
+{
+ int i, nparts, rc = 0, errfirst = 0, errlast = 0;
+
+ assert(fd >= 0);
+ assert(device);
+ assert(ls);
+
+ nparts = blkid_partlist_numof_partitions(ls);
+
+ for (i = 0; i < nparts; i++) {
+ blkid_partition par = blkid_partlist_get_partition(ls, i);
+ int n = blkid_partition_get_partno(par);
+ uintmax_t start, size;
+
+ if (lower && n < lower)
+ continue;
+ if (upper && n > upper)
+ continue;
+
+ start = blkid_partition_get_start(par);
+ size = blkid_partition_get_size(par);
+
+ if (blkid_partition_is_extended(par))
+ /*
+ * Let's follow Linux kernel and reduce
+ * DOS extended partition to 1 or 2 sectors
+ */
+ size = min(size, (uintmax_t) 2);
+
+ if (partx_add_partition(fd, n, start, size) == 0) {
+ if (verbose)
+ printf(_("%s: partition #%d added\n"), device, n);
+ continue;
+ }
+ rc = -1;
+ if (verbose)
+ warn(_("%s: add partition #%d failed"), device, n);
+ if (!errfirst)
+ errlast = errfirst = n;
+ else if (errlast + 1 == n)
+ errlast++;
+ else {
+ add_parts_warnx(device, errfirst, errlast);
+ errlast = errfirst = n;
+ }
}
- if (g.start != 0) {
- fprintf(stderr, "last arg is not the whole disk\n");
- fprintf(stderr, "call: partx -opts device wholedisk\n");
- exit(1);
+
+ if (errfirst)
+ add_parts_warnx(device, errfirst, errlast);
+ return rc;
+}
+
+static int list_parts(blkid_partlist ls, int lower, int upper)
+{
+ int i, nparts;
+
+ assert(ls);
+
+ nparts = blkid_partlist_numof_partitions(ls);
+
+ for (i = 0; i < nparts; i++) {
+ blkid_partition par = blkid_partlist_get_partition(ls, i);
+ int n = blkid_partition_get_partno(par);
+ uintmax_t start, size;
+
+ if (lower && n < lower)
+ continue;
+ if (upper && n > upper)
+ continue;
+
+ start = blkid_partition_get_start(par);
+ size = blkid_partition_get_size(par);
+
+ printf("#%2d: %9ju-%9ju (%9ju sectors, %6ju MB)\n",
+ n, start, start + size -1,
+ size, (size << 9) / 1000000);
}
+ return 0;
+}
+
+static void add_tt_line(struct tt *tt, blkid_partition par)
+{
+ struct tt_line *line;
+ int i;
+
+ assert(tt);
+ assert(par);
- if (ioctl(fd2, HDIO_GETGEO, &g)) {
- perror("HDIO_GETGEO");
- exit(1);
+ line = tt_add_line(tt, NULL);
+ if (!line) {
+ warn(_("failed to add line to output"));
+ return;
}
- all.start = g.start;
- if (blkdev_get_sectors(fd2, &size) != 0) {
- perror("partx");
- exit(1);
+ for (i = 0; i < ncolumns; i++) {
+ char *str = NULL;
+ int rc = 0;
+
+ switch (get_column_id(i)) {
+ case COL_PARTNO:
+ rc = asprintf(&str, "%d",
+ blkid_partition_get_partno(par));
+ break;
+ case COL_START:
+ rc = asprintf(&str, "%ju",
+ blkid_partition_get_start(par));
+ break;
+ case COL_END:
+ rc = asprintf(&str, "%ju",
+ blkid_partition_get_start(par) +
+ blkid_partition_get_size(par) - 1);
+ break;
+ case COL_SECTORS:
+ rc = asprintf(&str, "%ju",
+ blkid_partition_get_size(par));
+ break;
+ case COL_SIZE:
+ if (partx_flags & FL_BYTES)
+ rc = asprintf(&str, "%ju", (uintmax_t)
+ blkid_partition_get_size(par) << 9);
+ else {
+ str = size_to_human_string(
+ blkid_partition_get_size(par) << 9);
+ if (str)
+ rc = 1;
+ }
+ break;
+ case COL_NAME:
+ str = (char *) blkid_partition_get_name(par);
+ break;
+ case COL_UUID:
+ str = (char *) blkid_partition_get_uuid(par);
+ break;
+ case COL_TYPE:
+ if (blkid_partition_is_primary(par))
+ str = xstrdup("P"), rc = 1;
+ else if (blkid_partition_is_logical(par))
+ str = xstrdup("L"), rc = 1;
+ else if (blkid_partition_is_extended(par))
+ str = xstrdup("E"), rc = 1;
+ break;
+ default:
+ break;
+ }
+
+ if (str && rc)
+ tt_line_set_data(line, i, str);
}
- all.size = (unsigned int) size;
+}
- if (verbose)
- printf("device %s: start %d size %d\n",
- device, all.start, all.size);
+static int show_parts(blkid_partlist ls, int tt_flags, int lower, int upper)
+{
+ int i, rc = -1;
+ struct tt *tt;
+ int nparts;
- if (all.size == 0) {
- fprintf(stderr, "That disk slice has size 0\n");
- exit(0);
+ assert(ls);
+
+ nparts = blkid_partlist_numof_partitions(ls);
+ if (!nparts)
+ return 0;
+
+ tt = tt_new_table(tt_flags);
+ if (!tt) {
+ warn(_("failed to initialize output table"));
+ return -1;
}
- if (all.size == 2)
- all.size = 0; /* probably extended partition */
- /* add the indicated partitions to the kernel partition tables */
- if (!lower)
- lower = 1;
- for (i = 0; i < ptct; i++) {
- ptp = &pts[i];
- if (!type || !strcmp(type, ptp->type)) {
- n = ptp->fn(fd, all, slices, ARRAY_SIZE(slices));
- if (n >= 0 && verbose)
- printf("%s: %d slices\n", ptp->type, n);
- if (n > 0 && (verbose || what == LIST)) {
- for (j=0; j<n; j++)
- printf("#%2d: %9d-%9d (%9d sectors, %6d MB)\n",
- lower+j,
- slices[j].start,
- slices[j].start+slices[j].size-1,
- slices[j].size,
- (int)((512 * (long long) slices[j].size)
- / 1000000));
- }
- if (n > 0 && what == ADD) {
- /* test for overlap, as in the case of an
- extended partition, and reduce size */
- for (j=0; j<n; j++) {
- for (k=j+1; k<n; k++) {
- if (slices[k].start > slices[j].start &&
- slices[k].start < slices[j].start +
- slices[j].size) {
- slices[j].size = slices[k].start -
- slices[j].start;
- if (verbose)
- printf("reduced size of "
- "partition #%d to %d\n",
- lower+j,
- slices[j].size);
- }
- }
- }
- for (j=0; j<n; j++) {
- /* skip unused/empty partitions */
- if (slices[j].size == 0)
- continue;
- pt.pno = lower+j;
- pt.start = 512 * (long long) slices[j].start;
- pt.length = 512 * (long long) slices[j].size;
- pt.devname[0] = 0;
- pt.volname[0] = 0;
- a.op = BLKPG_ADD_PARTITION;
- a.flags = 0;
- a.datalen = sizeof(pt);
- a.data = &pt;
- if (ioctl(fd, BLKPG, &a) == -1) {
- perror("BLKPG");
- fprintf(stderr,
- "error adding partition %d\n",
- lower+j);
- } else if (verbose)
- printf("added partition %d\n", lower+j);
- }
- }
+ for (i = 0; i < ncolumns; i++) {
+ struct colinfo *col = get_column_info(i);
+
+ if (!tt_define_column(tt, col->name, col->whint, col->flags)) {
+ warnx(_("failed to initialize output column"));
+ goto done;
}
}
- return 0;
-}
+ for (i = 0; i < nparts; i++) {
+ blkid_partition par = blkid_partlist_get_partition(ls, i);
+ int n = blkid_partition_get_partno(par);
-static void *
-xmalloc (size_t size) {
- void *t;
+ if (lower && n < lower)
+ continue;
+ if (upper && n > upper)
+ continue;
- if (size == 0)
- return NULL;
- t = malloc (size);
- if (t == NULL) {
- fprintf(stderr, "Out of memory\n");
- exit(1);
+ add_tt_line(tt, par);
}
- return t;
+
+ rc = 0;
+ tt_print_table(tt);
+done:
+ tt_free_table(tt);
+ return rc;
}
-static int
-sseek(int fd, unsigned int secnr) {
- long long in, out;
- in = ((long long) secnr << 9);
- out = 1;
+static int parse_range(const char *str, int *lower, int *upper)
+{
+ char *end = NULL;
+
+ if (!str)
+ return 0;
- if ((out = lseek(fd, in, SEEK_SET)) != in)
- {
- fprintf(stderr, "lseek error\n");
- return -1;
+ *upper = *lower = 0;
+ errno = 0;
+
+ if (*str == ':') { /* <:N> */
+ str++;
+ *upper = strtol(str, &end, 10);
+ if (errno || !end || *end || end == str)
+ return -1;
+ } else {
+ *upper = *lower = strtol(str, &end, 10);
+ if (errno || !end || end == str)
+ return -1;
+
+ if (*end == ':' && !*(end + 1)) /* <M:> */
+ *upper = 0;
+ else if (*end == '-' || *end == ':') { /* <M:N> <M-N> */
+ str = end + 1;
+ end = NULL;
+ errno = 0;
+ *upper = strtol(str, &end, 10);
+
+ if (errno || !end || *end || end == str)
+ return -1;
+ }
}
return 0;
}
-static
-struct block {
- unsigned int secnr;
- unsigned char *block;
- struct block *next;
-} *blockhead;
-
-unsigned char *
-getblock(int fd, unsigned int secnr) {
- struct block *bp;
-
- for (bp = blockhead; bp; bp = bp->next)
- if (bp->secnr == secnr)
- return bp->block;
- if (sseek(fd, secnr))
+static blkid_partlist get_partlist(blkid_probe pr,
+ const char *device, char *type)
+{
+ blkid_partlist ls;
+ blkid_parttable tab;
+
+ assert(pr);
+ assert(device);
+
+ if (type) {
+ char *name[] = { type, NULL };
+
+ if (blkid_probe_filter_partitions_type(pr,
+ BLKID_FLTR_ONLYIN, name)) {
+ warnx(_("failed to initialize blkid "
+ "filter for '%s'"), type);
+ return NULL;
+ }
+ }
+
+ ls = blkid_probe_get_partitions(pr);
+ if (!ls) {
+ warnx(_("%s: failed to read partition table"), device);
+ return NULL;
+ }
+
+ tab = blkid_partlist_get_table(ls);
+ if (verbose && tab)
+ printf(_("%s: partition table '%s' detected\n"),
+ device,
+ blkid_parttable_get_type(tab));
+
+ if (!blkid_partlist_numof_partitions(ls)) {
+ warnx(_("%s: %s partition table does not contains "
+ "usable partitions"), device,
+ blkid_parttable_get_type(tab));
return NULL;
- bp = xmalloc(sizeof(struct block));
- bp->secnr = secnr;
- bp->next = blockhead;
- blockhead = bp;
- bp->block = (unsigned char *) xmalloc(1024);
- if (read(fd, bp->block, 1024) != 1024) {
- fprintf(stderr, "read error, sector %d\n", secnr);
- bp->block = NULL;
}
- return bp->block;
+ return ls;
+}
+
+static int __attribute__((__noreturn__)) usage(FILE *out)
+{
+ int i;
+
+ fprintf(out, _(
+ "\nUsage:\n"
+ " %s [-a|-d|-s] [--nr <N-M> | <device>] <wholedisk>\n"),
+ program_invocation_short_name);
+
+ fprintf(out, _(
+ "\nOptions:\n"
+ " -a, --add add specified partitions or all of them\n"
+ " -d, --delete delete specified partitions or all of them\n"
+ " -l, --list list partitions (DEPRECATED)\n"
+ " -s, --show list partitions\n\n"
+
+ " -b, --bytes print SIZE in bytes rather than in human readable format\n"
+ " -g, --noheadings don't print headings for --show\n"
+ " -r, --raw use raw format output\n"
+ " -t, --type <TYPE> specify the partition type (dos, bsd, solaris, etc.)\n"
+ " -n, --nr <M:N> specify the range of partitions (--nr 2:4)\n"
+ " -o, --output <LIST> output column\n"
+ " -h, --help print this help\n\n"));
+
+ fprintf(out, _("\nAvailable columns (for --show):\n"));
+
+ for (i = 0; i < __NCOLUMNS; i++)
+ fprintf(out, " %10s %s\n", infos[i].name, gettext(infos[i].help));
+
+ fprintf(out, _("\nFor more information see partx(8).\n"));
+
+ exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+static int __attribute__((__noreturn__))
+errx_mutually_exclusive(const char *opts)
+{
+ errx(EXIT_FAILURE, "%s %s", opts, _("options are mutually exclusive"));
}
-/* call with errno and integer m and error message */
-/* merge to interval m-n */
-static void
-errmerge(int err, int m, char *msg1, char *msg2) {
- static int preverr, firstm, prevm;
-
- if (err != preverr) {
- if (preverr) {
- if (firstm == prevm)
- fprintf(stderr, msg1, firstm);
- else
- fprintf(stderr, msg2, firstm, prevm);
- errno = preverr;
- perror("BLKPG");
+int main(int argc, char **argv)
+{
+ int fd, c, what = 0, lower = 0, upper = 0, rc = 0;
+ int tt_flags = 0;
+ char *type = NULL;
+ char *device = NULL; /* pointer to atgv[], ie: /dev/sda1 */
+ char *wholedisk = NULL; /* allocated, ie: /dev/sda */
+ dev_t disk_devno = 0, part_devno = 0;
+
+ static const struct option long_opts[] = {
+ { "bytes", no_argument, NULL, 'b' },
+ { "noheadings", no_argument, NULL, 'g' },
+ { "raw", no_argument, NULL, 'r' },
+ { "list", no_argument, NULL, 'l' },
+ { "show", no_argument, NULL, 's' },
+ { "add", no_argument, NULL, 'a' },
+ { "delete", no_argument, NULL, 'd' },
+ { "type", required_argument, NULL, 't' },
+ { "nr", required_argument, NULL, 'n' },
+ { "output", required_argument, NULL, 'o' },
+ { "help", no_argument, NULL, 'h' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ while ((c = getopt_long(argc, argv, "abdglrsvn:t:o:h", long_opts, NULL)) != -1) {
+ switch(c) {
+ case 'a':
+ if (what)
+ errx_mutually_exclusive("--{add,delete,show,list,raw}");
+ what = ACT_ADD;
+ break;
+ case 'b':
+ partx_flags |= FL_BYTES;
+ break;
+ case 'd':
+ if (what)
+ errx_mutually_exclusive("--{add,delete,show,list,raw}");
+ what = ACT_DELETE;
+ break;
+ case 'g':
+ tt_flags |= TT_FL_NOHEADINGS;
+ break;
+ case 'l':
+ if (what)
+ errx_mutually_exclusive("--{add,delete,show,list,raw}");
+ what = ACT_LIST;
+ break;
+ case 'n':
+ if (parse_range(optarg, &lower, &upper))
+ errx(EXIT_FAILURE, _("failed to parse --nr <M-N> range"));
+ break;
+
+ case 'o':
+ if (tt_parse_columns_list(optarg, columns, &ncolumns,
+ column_name_to_id))
+ return EXIT_FAILURE;
+ break;
+ case 'r':
+ tt_flags |= TT_FL_RAW;
+ if (what)
+ errx_mutually_exclusive("--{add,delete,show,list,raw}");
+ what = ACT_SHOW;
+ break;
+
+ case 's':
+ if (what)
+ errx_mutually_exclusive("--{add,delete,show,list,raw}");
+ what = ACT_SHOW;
+ break;
+ case 't':
+ type = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'h':
+ usage(stdout);
+ case '?':
+ default:
+ usage(stderr);
+ }
+ }
+
+ /* -o <list> enables --show mode by default */
+ if (ncolumns && !what)
+ what = ACT_SHOW;
+
+ /* backwardly compatible default */
+ if (!what)
+ what = ACT_LIST;
+
+ /* --show default, could by modified by -o */
+ if (what == ACT_SHOW && !ncolumns) {
+ columns[ncolumns++] = COL_PARTNO;
+ columns[ncolumns++] = COL_START;
+ columns[ncolumns++] = COL_END;
+ columns[ncolumns++] = COL_SECTORS;
+ columns[ncolumns++] = COL_SIZE;
+ columns[ncolumns++] = COL_NAME;
+ columns[ncolumns++] = COL_UUID;
+ }
+
+ /*
+ * Note that 'partx /dev/sda1' == 'partx /dev/sda1 /dev/sda'
+ * so assume that the device and/or disk are always the last
+ * arguments to be passed to partx.
+ */
+ if (optind == argc - 2) {
+ /* passed 2 arguments:
+ * /dev/sda1 /dev/sda : partition + whole-disk
+ * -- /dev/sda1 : partition that should be used as a whole-disk
+ */
+ device = argv[optind];
+
+ if (strcmp(device, "-") == 0) {
+ device = NULL;
+ wholedisk = xstrdup(argv[optind + 1]);
+ } else {
+ device = argv[optind];
+ wholedisk = xstrdup(argv[optind + 1]);
+ }
+ } else if (optind == argc - 1) {
+ /* passed only one arg (ie: /dev/sda3 or /dev/sda) */
+ struct stat sb;
+
+ device = argv[optind];
+
+ if (stat(device, &sb))
+ err(EXIT_FAILURE, _("%s: stat failed"), device);
+
+ part_devno = sb.st_rdev;
+
+ if (blkid_devno_to_wholedisk(part_devno,
+ NULL, 0, &disk_devno) == 0 &&
+ part_devno != disk_devno)
+ wholedisk = blkid_devno_to_devname(disk_devno);
+
+ if (!wholedisk) {
+ wholedisk = xstrdup(device);
+ disk_devno = part_devno;
+ device = NULL;
+ part_devno = 0;
}
- preverr = err;
- firstm = prevm = m;
} else
- prevm = m;
+ usage(stderr);
+
+ if (device && (upper || lower))
+ errx(EXIT_FAILURE, _("--nr and <partition> are mutually exclusive}"));
+
+ assert(wholedisk);
+
+ if (device) {
+ /* use partno from given partition instead of --nr range, e.g:
+ * partx -d /dev/sda3
+ * is the same like:
+ * partx -d --nr 3 /dev/sda
+ */
+ struct stat sb;
+
+ if (!part_devno && !stat(device, &sb))
+ part_devno = sb.st_rdev;
+
+ lower = upper = get_partno_from_device(device, part_devno);
+ }
+
+ if (verbose)
+ printf("device: %s, whole-disk: %s, lower: %d, upper: %d\n",
+ device, wholedisk, lower, upper);
+
+ if (what == ACT_ADD || what == ACT_DELETE) {
+ struct stat x;
+
+ if (stat(wholedisk, &x) || !S_ISBLK(x.st_mode))
+ errx(EXIT_FAILURE, _("%s: not a block device"), wholedisk);
+ }
+ if ((fd = open(wholedisk, O_RDONLY)) == -1)
+ err(EXIT_FAILURE, _("%s: open failed"), wholedisk);
+
+ if (what == ACT_DELETE)
+ rc = del_parts(fd, wholedisk, disk_devno, lower, upper);
+ else {
+ blkid_probe pr = blkid_new_probe();
+ blkid_partlist ls = NULL;
+
+ if (!pr || blkid_probe_set_device(pr, fd, 0, 0))
+ warnx(_("%s: failed to initialize blkid prober"),
+ wholedisk);
+ else
+ ls = get_partlist(pr, wholedisk, type);
+
+ if (ls) {
+ int n = blkid_partlist_numof_partitions(ls);
+
+ if (lower < 0)
+ lower = n + lower + 1;
+ if (upper < 0)
+ upper = n + upper + 1;
+ if (lower > upper) {
+ warnx(_("defined range <%d:%d> "
+ "does not make sense"), lower, upper);
+ rc = -1, what = 0;
+ }
+
+ switch (what) {
+ case ACT_SHOW:
+ rc = show_parts(ls, tt_flags, lower, upper);
+ break;
+ case ACT_LIST:
+ rc = list_parts(ls, lower, upper);
+ break;
+ case ACT_ADD:
+ rc = add_parts(fd, wholedisk, ls, lower, upper);
+ break;
+ }
+ }
+ blkid_free_probe(pr);
+ }
+
+ close(fd);
+ return rc ? EXIT_FAILURE : EXIT_SUCCESS;
}
+