]> err.no Git - util-linux/commitdiff
partx: complete rewrite
authorDavidlohr Bueso <dave@gnu.org>
Thu, 9 Dec 2010 20:54:17 +0000 (21:54 +0100)
committerKarel Zak <kzak@redhat.com>
Thu, 9 Dec 2010 20:54:17 +0000 (21:54 +0100)
Co-Author: Karel Zak <kzak@redhat.com>
Signed-off-by: Davidlohr Bueso <dave@gnu.org>
Signed-off-by: Karel Zak <kzak@redhat.com>
19 files changed:
include/strutils.h
lib/strutils.c
misc-utils/lsblk.c
partx/Makefile.am
partx/bsd.c [deleted file]
partx/crc32.c [deleted file]
partx/crc32.h [deleted file]
partx/dos.c [deleted file]
partx/dos.h [deleted file]
partx/efi.h [deleted file]
partx/gpt.c [deleted file]
partx/gpt.h [deleted file]
partx/mac.c [deleted file]
partx/partx.8
partx/partx.c
partx/partx.h
partx/solaris.c [deleted file]
partx/sun.c [deleted file]
partx/unixware.c [deleted file]

index 31cf80603da8c00935ff60d82ead171032f0af11..462332d9574ad8284c35060f929420c6dd9d2f25 100644 (file)
@@ -26,5 +26,6 @@ static inline void xstrncpy(char *dest, const char *src, size_t n)
 }
 
 extern void strmode(mode_t mode, char *str);
+extern char *size_to_human_string(uint64_t bytes);
 
 #endif
index dcae9f2d30b05f68f1d40d154f03eaa1c15506fb..e8e868653b4ce3e4a6f6075bfc5acacac8eeb56b 100644 (file)
@@ -3,12 +3,15 @@
  * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
  */
 
+#include <stdio.h>
 #include <stdlib.h>
 #include <inttypes.h>
 #include <ctype.h>
 #include <errno.h>
 #include <err.h>
 #include <sys/stat.h>
+#include <locale.h>
+#include <string.h>
 
 static int do_scale_by_power (uintmax_t *x, int base, int power)
 {
@@ -224,3 +227,49 @@ void strmode(mode_t mode, char *str)
                : (mode & S_IXOTH ? 'x' : '-'));
        str[10] = '\0';
 }
+
+/*
+ * returns exponent (2^x=n) in range KiB..PiB
+ */
+static int get_exp(uint64_t n)
+{
+       int shft;
+
+       for (shft = 10; shft <= 60; shft += 10) {
+               if (n < (1ULL << shft))
+                       break;
+       }
+       return shft - 10;
+}
+
+char *size_to_human_string(uint64_t bytes)
+{
+       char buf[32];
+       int dec, frac, exp;
+       const char *letters = "BKMGTP";
+       char c;
+
+       exp  = get_exp(bytes);
+       c    = *(letters + (exp ? exp / 10 : 0));
+       dec  = exp ? bytes / (1ULL << exp) : bytes;
+       frac = exp ? bytes % (1ULL << exp) : 0;
+
+       if (frac) {
+               /* round */
+               frac = (frac / (1ULL << (exp - 10)) + 50) / 100;
+               if (frac == 10)
+                       dec++, frac = 0;
+       }
+
+       if (frac) {
+               struct lconv const *l = localeconv();
+               char *dp = l ? l->decimal_point : NULL;
+
+               if (!dp || !*dp)
+                       dp = ".";
+               snprintf(buf, sizeof(buf), "%d%s%d%c", dec, dp, frac, c);
+       } else
+               snprintf(buf, sizeof(buf), "%d%c", dec, c);
+
+       return strdup(buf);
+}
index 6c5a205dbda115942c36431e7c7a7ff356c9c7c6..745a3e615f12d0fcd6712a06976c683c85e29fad 100644 (file)
@@ -235,52 +235,6 @@ static struct dirent *xreaddir(DIR *dp)
        return d;
 }
 
-/*
- * returns exponent (2^x=n) in range KiB..PiB
- */
-static int get_exp(uint64_t n)
-{
-       int shft;
-
-       for (shft = 10; shft <= 60; shft += 10) {
-               if (n < (1ULL << shft))
-                       break;
-       }
-       return shft - 10;
-}
-
-static char *size_to_human_string(uint64_t bytes)
-{
-       char buf[32];
-       int dec, frac, exp;
-       const char *letters = "BKMGTP";
-       char c;
-
-       exp  = get_exp(bytes);
-       c    = *(letters + (exp ? exp / 10 : 0));
-       dec  = exp ? bytes / (1ULL << exp) : bytes;
-       frac = exp ? bytes % (1ULL << exp) : 0;
-
-       if (frac) {
-               /* round */
-               frac = (frac / (1ULL << (exp - 10)) + 50) / 100;
-               if (frac == 10)
-                       dec++, frac = 0;
-       }
-
-       if (frac) {
-               struct lconv const *l = localeconv();
-               char *dp = l ? l->decimal_point : NULL;
-
-               if (!dp || !*dp)
-                       dp = ".";
-               snprintf(buf, sizeof(buf), "%d%s%d%c", dec, dp, frac, c);
-       } else
-               snprintf(buf, sizeof(buf), "%d%c", dec, c);
-
-       return xstrdup(buf);
-}
-
 
 static int is_partition_dirent(DIR *dir, struct dirent *d, const char *parent_name)
 {
index a26963ed8ff6c509f00638965d433b71cd2021f3..f7eeef88cbf2cf7b1273fd89b191efb8e7b6f1ae 100644 (file)
@@ -1,15 +1,23 @@
 include $(top_srcdir)/config/include-Makefile.am
 
-if BUILD_PARTX
+usrsbin_exec_PROGRAMS = addpart delpart
+dist_man_MANS = addpart.8 delpart.8
 
-usrsbin_exec_PROGRAMS = addpart delpart partx
-partx_SOURCES = bsd.c dos.c partx.c solaris.c unixware.c sun.c mac.c gpt.c crc32.c \
-               efi.h gpt.h crc32.h partx.h dos.h $(top_srcdir)/lib/blkdev.c
+if BUILD_PARTX
+if BUILD_LIBBLKID
+usrsbin_exec_PROGRAMS += partx
+partx_SOURCES = partx.c partx.h \
+               $(top_srcdir)/lib/blkdev.c \
+               $(top_srcdir)/lib/tt.c \
+               $(top_srcdir)/lib/strutils.c
 
 if LINUX
 partx_SOURCES += $(top_srcdir)/lib/linux_version.c
 endif
 
-dist_man_MANS = addpart.8 delpart.8 partx.8
-
+partx_CFLAGS = -I$(ul_libblkid_incdir)
+partx_LDADD = $(ul_libblkid_la)
+dist_man_MANS += partx.8
 endif
+endif
+
diff --git a/partx/bsd.c b/partx/bsd.c
deleted file mode 100644 (file)
index 4532c32..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-#include <stdio.h>
-#include "partx.h"
-
-#define BSD_DISKMAGIC  (0x82564557UL)  /* The disk magic number */
-#define XBSD_MAXPARTITIONS     16
-#define BSD_FS_UNUSED          0
-
-struct bsd_disklabel {
-       unsigned int    d_magic;        /* the magic number */
-       short int       d_type;         /* drive type */
-       short int       d_subtype;      /* controller/d_type specific */
-       char    d_typename[16];         /* type name, e.g. "eagle" */
-       char    d_packname[16];         /* pack identifier */ 
-       unsigned int    d_secsize;      /* # of bytes per sector */
-       unsigned int    d_nsectors;     /* # of data sectors per track */
-       unsigned int    d_ntracks;      /* # of tracks per cylinder */
-       unsigned int    d_ncylinders;   /* # of data cylinders per unit */
-       unsigned int    d_secpercyl;    /* # of data sectors per cylinder */
-       unsigned int    d_secperunit;   /* # of data sectors per unit */
-       unsigned short  d_sparespertrack;/* # of spare sectors per track */
-       unsigned short  d_sparespercyl; /* # of spare sectors per cylinder */
-       unsigned int    d_acylinders;   /* # of alt. cylinders per unit */
-       unsigned short  d_rpm;          /* rotational speed */
-       unsigned short  d_interleave;   /* hardware sector interleave */
-       unsigned short  d_trackskew;    /* sector 0 skew, per track */
-       unsigned short  d_cylskew;      /* sector 0 skew, per cylinder */
-       unsigned int    d_headswitch;   /* head switch time, usec */
-       unsigned int    d_trkseek;      /* track-to-track seek, usec */
-       unsigned int    d_flags;        /* generic flags */
-       unsigned int    d_drivedata[5]; /* drive-type specific information */
-       unsigned int    d_spare[5];     /* reserved for future use */
-       unsigned int    d_magic2;       /* the magic number (again) */
-       unsigned short  d_checksum;     /* xor of data incl. partitions */
-
-                       /* filesystem and partition information: */
-       unsigned short  d_npartitions;  /* number of partitions in following */
-       unsigned int    d_bbsize;       /* size of boot area at sn0, bytes */
-       unsigned int    d_sbsize;       /* max size of fs superblock, bytes */
-       struct  bsd_partition {         /* the partition table */
-               unsigned int    p_size;   /* number of sectors in partition */
-               unsigned int    p_offset; /* starting sector */
-               unsigned int    p_fsize;  /* filesystem basic fragment size */
-               unsigned char   p_fstype; /* filesystem type, see below */
-               unsigned char   p_frag;   /* filesystem fragments per block */
-               unsigned short  p_cpg;    /* filesystem cylinders per group */
-       } d_partitions[XBSD_MAXPARTITIONS];/* actually may be more */
-};
-
-int
-read_bsd_pt(int fd, struct slice all, struct slice *sp, int ns) {
-       struct bsd_disklabel *l;
-       struct bsd_partition *p;
-       unsigned int offset = all.start;
-       int max_partitions;
-       unsigned char *bp;
-       int n = 0;
-
-       bp = getblock(fd, offset+1);    /* 1 sector suffices */
-       if (bp == NULL)
-               return -1;
-
-       l = (struct bsd_disklabel *) bp;
-       if (l->d_magic != BSD_DISKMAGIC)
-               return -1;
-
-       max_partitions = 16;
-       if (l->d_npartitions < max_partitions)
-               max_partitions = l->d_npartitions;
-       for (p = l->d_partitions; p - l->d_partitions <  max_partitions; p++) {
-               if (p->p_fstype == BSD_FS_UNUSED)
-                       /* nothing */;
-               else if (n < ns) {
-                       sp[n].start = p->p_offset;
-                       sp[n].size = p->p_size;
-                       n++;
-               } else {
-                       fprintf(stderr,
-                               "bsd_partition: too many slices\n");
-                       break;
-               }
-       }
-       return n;
-}
diff --git a/partx/crc32.c b/partx/crc32.c
deleted file mode 100644 (file)
index 4120f72..0000000
+++ /dev/null
@@ -1,393 +0,0 @@
-/* 
- * crc32.c
- * This code is in the public domain; copyright abandoned.
- * Liability for non-performance of this code is limited to the amount
- * you paid for it.  Since it is distributed for free, your refund will
- * be very very small.  If it breaks, you get to keep both pieces.
- */
-
-#include "crc32.h"
-
-#if __GNUC__ >= 3      /* 2.x has "attribute", but only 3.0 has "pure */
-#define attribute(x) __attribute__(x)
-#else
-#define attribute(x)
-#endif
-
-/*
- * There are multiple 16-bit CRC polynomials in common use, but this is
- * *the* standard CRC-32 polynomial, first popularized by Ethernet.
- * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
- */
-#define CRCPOLY_LE 0xedb88320
-#define CRCPOLY_BE 0x04c11db7
-
-/* How many bits at a time to use.  Requires a table of 4<<CRC_xx_BITS bytes. */
-/* For less performance-sensitive, use 4 */
-#define CRC_LE_BITS 8
-#define CRC_BE_BITS 8
-
-/*
- * Little-endian CRC computation.  Used with serial bit streams sent
- * lsbit-first.  Be sure to use cpu_to_le32() to append the computed CRC.
- */
-#if CRC_LE_BITS > 8 || CRC_LE_BITS < 1 || CRC_LE_BITS & CRC_LE_BITS-1
-# error CRC_LE_BITS must be a power of 2 between 1 and 8
-#endif
-
-#if CRC_LE_BITS == 1
-/*
- * In fact, the table-based code will work in this case, but it can be
- * simplified by inlining the table in ?: form.
- */
-#define crc32init_le()
-#define crc32cleanup_le()
-/**
- * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
- * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
- *        other uses, or the previous crc32 value if computing incrementally.
- * @p   - pointer to buffer over which CRC is run
- * @len - length of buffer @p
- * 
- */
-uint32_t attribute((pure)) crc32_le(uint32_t crc, unsigned char const *p, size_t len)
-{
-       int i;
-       while (len--) {
-               crc ^= *p++;
-               for (i = 0; i < 8; i++)
-                       crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
-       }
-       return crc;
-}
-#else                          /* Table-based approach */
-
-static uint32_t *crc32table_le;
-/**
- * crc32init_le() - allocate and initialize LE table data
- *
- * crc is the crc of the byte i; other entries are filled in based on the
- * fact that crctable[i^j] = crctable[i] ^ crctable[j].
- *
- */
-static int
-crc32init_le(void)
-{
-       unsigned i, j;
-       uint32_t crc = 1;
-
-       crc32table_le =
-               malloc((1 << CRC_LE_BITS) * sizeof(uint32_t));
-       if (!crc32table_le)
-               return 1;
-       crc32table_le[0] = 0;
-
-       for (i = 1 << (CRC_LE_BITS - 1); i; i >>= 1) {
-               crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
-               for (j = 0; j < 1 << CRC_LE_BITS; j += 2 * i)
-                       crc32table_le[i + j] = crc ^ crc32table_le[j];
-       }
-       return 0;
-}
-
-/**
- * crc32cleanup_le(): free LE table data
- */
-static void
-crc32cleanup_le(void)
-{
-       free(crc32table_le);
-       crc32table_le = NULL;
-}
-
-/**
- * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
- * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
- *        other uses, or the previous crc32 value if computing incrementally.
- * @p   - pointer to buffer over which CRC is run
- * @len - length of buffer @p
- * 
- */
-uint32_t attribute((pure)) crc32_le(uint32_t crc, unsigned char const *p, size_t len)
-{
-       while (len--) {
-# if CRC_LE_BITS == 8
-               crc = (crc >> 8) ^ crc32table_le[(crc ^ *p++) & 255];
-# elif CRC_LE_BITS == 4
-               crc ^= *p++;
-               crc = (crc >> 4) ^ crc32table_le[crc & 15];
-               crc = (crc >> 4) ^ crc32table_le[crc & 15];
-# elif CRC_LE_BITS == 2
-               crc ^= *p++;
-               crc = (crc >> 2) ^ crc32table_le[crc & 3];
-               crc = (crc >> 2) ^ crc32table_le[crc & 3];
-               crc = (crc >> 2) ^ crc32table_le[crc & 3];
-               crc = (crc >> 2) ^ crc32table_le[crc & 3];
-# endif
-       }
-       return crc;
-}
-#endif
-
-/*
- * Big-endian CRC computation.  Used with serial bit streams sent
- * msbit-first.  Be sure to use cpu_to_be32() to append the computed CRC.
- */
-#if CRC_BE_BITS > 8 || CRC_BE_BITS < 1 || CRC_BE_BITS & CRC_BE_BITS-1
-# error CRC_BE_BITS must be a power of 2 between 1 and 8
-#endif
-
-#if CRC_BE_BITS == 1
-/*
- * In fact, the table-based code will work in this case, but it can be
- * simplified by inlining the table in ?: form.
- */
-#define crc32init_be()
-#define crc32cleanup_be()
-
-/**
- * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
- * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
- *        other uses, or the previous crc32 value if computing incrementally.
- * @p   - pointer to buffer over which CRC is run
- * @len - length of buffer @p
- * 
- */
-uint32_t attribute((pure)) crc32_be(uint32_t crc, unsigned char const *p, size_t len)
-{
-       int i;
-       while (len--) {
-               crc ^= *p++ << 24;
-               for (i = 0; i < 8; i++)
-                       crc =
-                           (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE :
-                                         0);
-       }
-       return crc;
-}
-
-#else                          /* Table-based approach */
-static uint32_t *crc32table_be;
-
-/**
- * crc32init_be() - allocate and initialize BE table data
- */
-static int
-crc32init_be(void)
-{
-       unsigned i, j;
-       uint32_t crc = 0x80000000;
-
-       crc32table_be =
-               malloc((1 << CRC_BE_BITS) * sizeof(uint32_t));
-       if (!crc32table_be)
-               return 1;
-       crc32table_be[0] = 0;
-
-       for (i = 1; i < 1 << CRC_BE_BITS; i <<= 1) {
-               crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
-               for (j = 0; j < i; j++)
-                       crc32table_be[i + j] = crc ^ crc32table_be[j];
-       }
-       return 0;
-}
-
-/**
- * crc32cleanup_be(): free BE table data
- */
-static void
-crc32cleanup_be(void)
-{
-       free(crc32table_be);
-       crc32table_be = NULL;
-}
-
-
-/**
- * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
- * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
- *        other uses, or the previous crc32 value if computing incrementally.
- * @p   - pointer to buffer over which CRC is run
- * @len - length of buffer @p
- * 
- */
-uint32_t attribute((pure)) crc32_be(uint32_t crc, unsigned char const *p, size_t len)
-{
-       while (len--) {
-# if CRC_BE_BITS == 8
-               crc = (crc << 8) ^ crc32table_be[(crc >> 24) ^ *p++];
-# elif CRC_BE_BITS == 4
-               crc ^= *p++ << 24;
-               crc = (crc << 4) ^ crc32table_be[crc >> 28];
-               crc = (crc << 4) ^ crc32table_be[crc >> 28];
-# elif CRC_BE_BITS == 2
-               crc ^= *p++ << 24;
-               crc = (crc << 2) ^ crc32table_be[crc >> 30];
-               crc = (crc << 2) ^ crc32table_be[crc >> 30];
-               crc = (crc << 2) ^ crc32table_be[crc >> 30];
-               crc = (crc << 2) ^ crc32table_be[crc >> 30];
-# endif
-       }
-       return crc;
-}
-#endif
-
-/*
- * A brief CRC tutorial.
- *
- * A CRC is a long-division remainder.  You add the CRC to the message,
- * and the whole thing (message+CRC) is a multiple of the given
- * CRC polynomial.  To check the CRC, you can either check that the
- * CRC matches the recomputed value, *or* you can check that the
- * remainder computed on the message+CRC is 0.  This latter approach
- * is used by a lot of hardware implementations, and is why so many
- * protocols put the end-of-frame flag after the CRC.
- *
- * It's actually the same long division you learned in school, except that
- * - We're working in binary, so the digits are only 0 and 1, and
- * - When dividing polynomials, there are no carries.  Rather than add and
- *   subtract, we just xor.  Thus, we tend to get a bit sloppy about
- *   the difference between adding and subtracting.
- *
- * A 32-bit CRC polynomial is actually 33 bits long.  But since it's
- * 33 bits long, bit 32 is always going to be set, so usually the CRC
- * is written in hex with the most significant bit omitted.  (If you're
- * familiar with the IEEE 754 floating-point format, it's the same idea.)
- *
- * Note that a CRC is computed over a string of *bits*, so you have
- * to decide on the endianness of the bits within each byte.  To get
- * the best error-detecting properties, this should correspond to the
- * order they're actually sent.  For example, standard RS-232 serial is
- * little-endian; the most significant bit (sometimes used for parity)
- * is sent last.  And when appending a CRC word to a message, you should
- * do it in the right order, matching the endianness.
- *
- * Just like with ordinary division, the remainder is always smaller than
- * the divisor (the CRC polynomial) you're dividing by.  Each step of the
- * division, you take one more digit (bit) of the dividend and append it
- * to the current remainder.  Then you figure out the appropriate multiple
- * of the divisor to subtract to being the remainder back into range.
- * In binary, it's easy - it has to be either 0 or 1, and to make the
- * XOR cancel, it's just a copy of bit 32 of the remainder.
- *
- * When computing a CRC, we don't care about the quotient, so we can
- * throw the quotient bit away, but subtract the appropriate multiple of
- * the polynomial from the remainder and we're back to where we started,
- * ready to process the next bit.
- *
- * A big-endian CRC written this way would be coded like:
- * for (i = 0; i < input_bits; i++) {
- *     multiple = remainder & 0x80000000 ? CRCPOLY : 0;
- *     remainder = (remainder << 1 | next_input_bit()) ^ multiple;
- * }
- * Notice how, to get at bit 32 of the shifted remainder, we look
- * at bit 31 of the remainder *before* shifting it.
- *
- * But also notice how the next_input_bit() bits we're shifting into
- * the remainder don't actually affect any decision-making until
- * 32 bits later.  Thus, the first 32 cycles of this are pretty boring.
- * Also, to add the CRC to a message, we need a 32-bit-long hole for it at
- * the end, so we have to add 32 extra cycles shifting in zeros at the
- * end of every message,
- *
- * So the standard trick is to rearrage merging in the next_input_bit()
- * until the moment it's needed.  Then the first 32 cycles can be precomputed,
- * and merging in the final 32 zero bits to make room for the CRC can be
- * skipped entirely.
- * This changes the code to:
- * for (i = 0; i < input_bits; i++) {
- *      remainder ^= next_input_bit() << 31;
- *     multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
- *     remainder = (remainder << 1) ^ multiple;
- * }
- * With this optimization, the little-endian code is simpler:
- * for (i = 0; i < input_bits; i++) {
- *      remainder ^= next_input_bit();
- *     multiple = (remainder & 1) ? CRCPOLY : 0;
- *     remainder = (remainder >> 1) ^ multiple;
- * }
- *
- * Note that the other details of endianness have been hidden in CRCPOLY
- * (which must be bit-reversed) and next_input_bit().
- *
- * However, as long as next_input_bit is returning the bits in a sensible
- * order, we can actually do the merging 8 or more bits at a time rather
- * than one bit at a time:
- * for (i = 0; i < input_bytes; i++) {
- *     remainder ^= next_input_byte() << 24;
- *     for (j = 0; j < 8; j++) {
- *             multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
- *             remainder = (remainder << 1) ^ multiple;
- *     }
- * }
- * Or in little-endian:
- * for (i = 0; i < input_bytes; i++) {
- *     remainder ^= next_input_byte();
- *     for (j = 0; j < 8; j++) {
- *             multiple = (remainder & 1) ? CRCPOLY : 0;
- *             remainder = (remainder << 1) ^ multiple;
- *     }
- * }
- * If the input is a multiple of 32 bits, you can even XOR in a 32-bit
- * word at a time and increase the inner loop count to 32.
- *
- * You can also mix and match the two loop styles, for example doing the
- * bulk of a message byte-at-a-time and adding bit-at-a-time processing
- * for any fractional bytes at the end.
- *
- * The only remaining optimization is to the byte-at-a-time table method.
- * Here, rather than just shifting one bit of the remainder to decide
- * in the correct multiple to subtract, we can shift a byte at a time.
- * This produces a 40-bit (rather than a 33-bit) intermediate remainder,
- * but again the multiple of the polynomial to subtract depends only on
- * the high bits, the high 8 bits in this case.  
- *
- * The multile we need in that case is the low 32 bits of a 40-bit
- * value whose high 8 bits are given, and which is a multiple of the
- * generator polynomial.  This is simply the CRC-32 of the given
- * one-byte message.
- *
- * Two more details: normally, appending zero bits to a message which
- * is already a multiple of a polynomial produces a larger multiple of that
- * polynomial.  To enable a CRC to detect this condition, it's common to
- * invert the CRC before appending it.  This makes the remainder of the
- * message+crc come out not as zero, but some fixed non-zero value.
- *
- * The same problem applies to zero bits prepended to the message, and
- * a similar solution is used.  Instead of starting with a remainder of
- * 0, an initial remainder of all ones is used.  As long as you start
- * the same way on decoding, it doesn't make a difference.
- */
-
-
-/**
- * init_crc32(): generates CRC32 tables
- * 
- * On successful initialization, use count is increased.
- * This guarantees that the library functions will stay resident
- * in memory, and prevents someone from 'rmmod crc32' while
- * a driver that needs it is still loaded.
- * This also greatly simplifies drivers, as there's no need
- * to call an initialization/cleanup function from each driver.
- * Since crc32.o is a library module, there's no requirement
- * that the user can unload it.
- */
-int
-init_crc32(void)
-{
-       int rc1, rc2, rc;
-       rc1 = crc32init_le();
-       rc2 = crc32init_be();
-       rc = rc1 || rc2;
-       return rc;
-}
-
-/**
- * cleanup_crc32(): frees crc32 data when no longer needed
- */
-void
-cleanup_crc32(void)
-{
-       crc32cleanup_le();
-       crc32cleanup_be();
-}
diff --git a/partx/crc32.h b/partx/crc32.h
deleted file mode 100644 (file)
index a4505b8..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * crc32.h
- */
-#ifndef _CRC32_H
-#define _CRC32_H
-
-#include <inttypes.h>
-#include <stdlib.h>
-
-extern int init_crc32(void);
-extern void cleanup_crc32(void);
-extern uint32_t  crc32_le(uint32_t crc, unsigned char const *p, size_t len);
-extern uint32_t  crc32_be(uint32_t crc, unsigned char const *p, size_t len);
-
-#define crc32(seed, data, length)  crc32_le(seed, (unsigned char const *)data, length)
-#define ether_crc_le(length, data) crc32_le(~0, data, length)
-#define ether_crc(length, data)    crc32_be(~0, data, length)
-
-#endif /* _CRC32_H */
diff --git a/partx/dos.c b/partx/dos.c
deleted file mode 100644 (file)
index f962f37..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-#include <stdio.h>
-
-#include "blkdev.h"
-
-#include "partx.h"
-#include "dos.h"
-
-static int
-is_extended(int type) {
-       return (type == 5 || type == 0xf || type == 0x85);
-}
-
-/* assemble badly aligned little endian integer */
-static inline unsigned int
-assemble4le(unsigned char *p) {
-       return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
-}
-
-static inline unsigned int
-partition_start(struct partition *p) {
-       return assemble4le(&(p->start_sect[0]));
-}
-
-static inline unsigned int
-partition_size(struct partition *p) {
-       return assemble4le(&(p->nr_sects[0]));
-}
-
-static int
-read_extended_partition(int fd, struct partition *ep,
-                       struct slice *sp, int ns, int ssf)
-{
-       struct partition *p;
-       unsigned long start, here;
-       unsigned char *bp;
-       int loopct = 0;
-       int moretodo = 1;
-       int i, n=0;
-
-       here = start = partition_start(ep);;
-
-       while (moretodo) {
-               moretodo = 0;
-               if (++loopct > 100)
-                       return n;
-
-               bp = getblock(fd, here * ssf);  /* in 512 blocks */
-               if (bp == NULL)
-                       return n;
-
-               if (bp[510] != 0x55 || bp[511] != 0xaa)
-                       return n;
-
-               p = (struct partition *) (bp + 0x1be);
-
-               for (i=0; i<2; i++, p++) {
-                       if (partition_size(p) == 0 || is_extended(p->sys_type))
-                               continue;
-                       if (n < ns) {
-                               sp[n].start = (here + partition_start(p)) * ssf;
-                               sp[n].size = partition_size(p) * ssf;
-                               n++;
-                       } else {
-                               fprintf(stderr,
-                                   "dos_extd_partition: too many slices\n");
-                               return n;
-                       }
-                       loopct = 0;
-               }
-
-               p -= 2;
-               for (i=0; i<2; i++, p++) {
-                       if (partition_size(p) != 0 &&
-                           is_extended(p->sys_type)) {
-                               here = start + partition_start(p);
-                               moretodo = 1;
-                               break;
-                       }
-               }
-       }
-       return n;
-}
-
-static int
-is_gpt(int type) {
-       return (type == 0xEE);
-}
-
-int
-read_dos_pt(int fd, struct slice all, struct slice *sp, int ns) {
-       struct partition *p;
-       unsigned long offset = all.start;
-       int i, n=0;
-       unsigned char *bp;
-       int ssf;
-
-       bp = getblock(fd, offset);
-       if (bp == NULL)
-               return -1;
-
-       if (bp[510] != 0x55 || bp[511] != 0xaa)
-               return -1;
-
-       /* msdos PT depends sector size... */
-       if (blkdev_get_sector_size(fd, &ssf) != 0)
-               ssf = DEFAULT_SECTOR_SIZE;
-
-       /* ... but partx counts everything in 512-byte sectors */
-       ssf /= 512;
-
-       p = (struct partition *) (bp + 0x1be);
-       for (i=0; i<4; i++) {
-               if (is_gpt(p->sys_type))
-                       return 0;
-               p++;
-       }
-       p = (struct partition *) (bp + 0x1be);
-       for (i=0; i<4; i++) {
-               /* always add, even if zero length */
-               if (n < ns) {
-                       sp[n].start = partition_start(p) * ssf;
-                       sp[n].size = partition_size(p) * ssf;
-                       n++;
-               } else {
-                       fprintf(stderr,
-                               "dos_partition: too many slices\n");
-                       break;
-               }
-               p++;
-       }
-       p = (struct partition *) (bp + 0x1be);
-       for (i=0; i<4; i++) {
-               if (is_extended(p->sys_type))
-                       n += read_extended_partition(fd, p, sp+n, ns-n, ssf);
-               p++;
-       }
-       return n;
-}
diff --git a/partx/dos.h b/partx/dos.h
deleted file mode 100644 (file)
index 877beec..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef DOS_H_INCLUDED
-#define DOS_H_INCLUDED
-
-struct partition {
-       unsigned char boot_ind; /* 0x80 - active */
-       unsigned char bh, bs, bc;
-       unsigned char sys_type;
-       unsigned char eh, es, ec;
-       unsigned char start_sect[4];
-       unsigned char nr_sects[4];
-};
-
-#endif                         /* DOS_H_INCLUDED */
diff --git a/partx/efi.h b/partx/efi.h
deleted file mode 100644 (file)
index fcf2740..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-  efi.[ch] - Manipulates EFI variables as exported in /proc/efi/vars
-  Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifndef EFI_H
-#define EFI_H
-
-/*
- * Extensible Firmware Interface
- * Based on 'Extensible Firmware Interface Specification'
- *      version 1.02, 12 December, 2000
- */
-#include <stdint.h>
-
-typedef struct {
-       uint8_t  b[16];
-} efi_guid_t;
-
-#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \
-((efi_guid_t) \
-{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
-  (b) & 0xff, ((b) >> 8) & 0xff, \
-  (c) & 0xff, ((c) >> 8) & 0xff, \
-  (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
-
-
-/******************************************************
- * GUIDs
- ******************************************************/
-#define NULL_GUID \
-EFI_GUID( 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
-
-static inline int
-efi_guidcmp(efi_guid_t left, efi_guid_t right)
-{
-       return memcmp(&left, &right, sizeof (efi_guid_t));
-}
-
-typedef uint16_t efi_char16_t;         /* UNICODE character */
-
-#endif /* EFI_H */
diff --git a/partx/gpt.c b/partx/gpt.c
deleted file mode 100644 (file)
index be612fc..0000000
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
-    gpt.[ch]
-
-    Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@dell.com>
-
-    EFI GUID Partition Table handling
-    Per Intel EFI Specification v1.02
-    http://developer.intel.com/technology/efi/efi.htm
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include "blkdev.h"
-#include "crc32.h"
-#include "gpt.h"
-#include "partx.h"
-#include "bitops.h"
-
-static inline uint32_t
-efi_crc32(const void *buf, unsigned long len)
-{
-       return (crc32(~0L, buf, len) ^ ~0L);
-}
-
-/**
- * is_pmbr_valid(): test Protective MBR for validity
- * @mbr: pointer to a legacy mbr structure
- *
- * Description: Returns 1 if PMBR is valid, 0 otherwise.
- * Validity depends on two things:
- *  1) MSDOS signature is in the last two bytes of the MBR
- *  2) One partition of type 0xEE is found
- */
-static int
-is_pmbr_valid(legacy_mbr *mbr)
-{
-       int i, found = 0, signature = 0;
-       if (!mbr)
-               return 0;
-       signature = (le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE);
-       for (i = 0; signature && i < 4; i++) {
-               if (mbr->partition[i].sys_type ==
-                    EFI_PMBR_OSTYPE_EFI_GPT) {
-                       found = 1;
-                       break;
-               }
-       }
-       return (signature && found);
-}
-
-static int
-get_sector_size (int fd)
-{
-       int sector_size;
-
-       if (blkdev_get_sector_size(fd, &sector_size) == -1)
-               return DEFAULT_SECTOR_SIZE;
-       return sector_size;
-}
-
-static uint64_t
-get_num_sectors(int fd)
-{
-       unsigned long long bytes=0;
-
-       if (blkdev_get_size(fd, &bytes) == -1)
-               return 0;
-       return bytes / get_sector_size(fd);
-}
-
-static uint64_t
-last_lba(int filedes)
-{
-       int rc;
-       uint64_t sectors = 0;
-       struct stat s;
-       memset(&s, 0, sizeof (s));
-       rc = fstat(filedes, &s);
-       if (rc == -1) {
-               fprintf(stderr, "last_lba() could not stat: %s\n",
-                       strerror(errno));
-               return 0;
-       }
-
-       if (S_ISBLK(s.st_mode)) {
-               sectors = get_num_sectors(filedes);
-       } else {
-               fprintf(stderr,
-                       "last_lba(): I don't know how to handle files with mode %x\n",
-                       s.st_mode);
-               sectors = 1;
-       }
-
-       return sectors - 1;
-}
-
-static ssize_t
-read_lba(int fd, uint64_t lba, void *buffer, size_t bytes)
-{
-       int sector_size = get_sector_size(fd);
-       off_t offset = lba * sector_size;
-
-       lseek(fd, offset, SEEK_SET);
-       return read(fd, buffer, bytes);
-}
-
-/**
- * alloc_read_gpt_entries(): reads partition entries from disk
- * @fd  is an open file descriptor to the whole disk
- * @gpt is a buffer into which the GPT will be put  
- * Description: Returns ptes on success,  NULL on error.
- * Allocates space for PTEs based on information found in @gpt.
- * Notes: remember to free pte when you're done!
- */
-static gpt_entry *
-alloc_read_gpt_entries(int fd, gpt_header * gpt)
-{
-       gpt_entry *pte;
-        size_t count = le32_to_cpu(gpt->num_partition_entries) *
-                le32_to_cpu(gpt->sizeof_partition_entry);
-
-        if (!count) return NULL;
-
-       pte = (gpt_entry *)malloc(count);
-       if (!pte)
-               return NULL;
-       memset(pte, 0, count);
-
-       if (!read_lba(fd, le64_to_cpu(gpt->partition_entry_lba), pte,
-                      count)) {
-               free(pte);
-               return NULL;
-       }
-       return pte;
-}
-
-/**
- * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk
- * @fd  is an open file descriptor to the whole disk
- * @lba is the Logical Block Address of the partition table
- * 
- * Description: returns GPT header on success, NULL on error.   Allocates
- * and fills a GPT header starting at @ from @bdev.
- * Note: remember to free gpt when finished with it.
- */
-static gpt_header *
-alloc_read_gpt_header(int fd, uint64_t lba)
-{
-       gpt_header *gpt;
-       gpt = (gpt_header *)
-           malloc(sizeof (gpt_header));
-       if (!gpt)
-               return NULL;
-       memset(gpt, 0, sizeof (*gpt));
-       if (!read_lba(fd, lba, gpt, sizeof (gpt_header))) {
-               free(gpt);
-               return NULL;
-       }
-
-       return gpt;
-}
-
-/**
- * is_gpt_valid() - tests one GPT header and PTEs for validity
- * @fd  is an open file descriptor to the whole disk
- * @lba is the logical block address of the GPT header to test
- * @gpt is a GPT header ptr, filled on return.
- * @ptes is a PTEs ptr, filled on return.
- *
- * Description: returns 1 if valid,  0 on error.
- * If valid, returns pointers to newly allocated GPT header and PTEs.
- */
-static int
-is_gpt_valid(int fd, uint64_t lba,
-             gpt_header ** gpt, gpt_entry ** ptes)
-{
-       int rc = 0;             /* default to not valid */
-       uint32_t crc, origcrc;
-
-       if (!gpt || !ptes)
-                return 0;
-       if (!(*gpt = alloc_read_gpt_header(fd, lba)))
-               return 0;
-
-       /* Check the GUID Partition Table signature */
-       if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
-               /* 
-                  printf("GUID Partition Table Header signature is wrong: %" PRIx64" != %" PRIx64 "\n",
-                  le64_to_cpu((*gpt)->signature), GUID_PT_HEADER_SIGNATURE);
-                */
-               free(*gpt);
-               *gpt = NULL;
-               return rc;
-       }
-
-       /* Check the GUID Partition Table Header CRC */
-       origcrc = le32_to_cpu((*gpt)->header_crc32);
-       (*gpt)->header_crc32 = 0;
-       crc = efi_crc32(*gpt, le32_to_cpu((*gpt)->header_size));
-       if (crc != origcrc) {
-               /* printf( "GPTH CRC check failed, %x != %x.\n", origcrc, crc); */
-               (*gpt)->header_crc32 = cpu_to_le32(origcrc);
-               free(*gpt);
-               *gpt = NULL;
-               return 0;
-       }
-       (*gpt)->header_crc32 = cpu_to_le32(origcrc);
-
-       /* Check that the my_lba entry points to the LBA
-        * that contains the GPT we read */
-       if (le64_to_cpu((*gpt)->my_lba) != lba) {
-               /* printf( "my_lba % PRIx64 "x != lba %"PRIx64 "x.\n", le64_to_cpu((*gpt)->my_lba), lba); */
-               free(*gpt);
-               *gpt = NULL;
-               return 0;
-       }
-
-       if (!(*ptes = alloc_read_gpt_entries(fd, *gpt))) {
-               free(*gpt);
-               *gpt = NULL;
-               return 0;
-       }
-
-       /* Check the GUID Partition Entry Array CRC */
-       crc = efi_crc32(*ptes,
-                        le32_to_cpu((*gpt)->num_partition_entries) *
-                       le32_to_cpu((*gpt)->sizeof_partition_entry));
-       if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
-               /* printf("GUID Partitition Entry Array CRC check failed.\n"); */
-               free(*gpt);
-               *gpt = NULL;
-               free(*ptes);
-               *ptes = NULL;
-               return 0;
-       }
-
-       /* We're done, all's well */
-       return 1;
-}
-/**
- * compare_gpts() - Search disk for valid GPT headers and PTEs
- * @pgpt is the primary GPT header
- * @agpt is the alternate GPT header
- * @lastlba is the last LBA number
- * Description: Returns nothing.  Sanity checks pgpt and agpt fields
- * and prints warnings on discrepancies.
- *
- */
-static void
-compare_gpts(gpt_header *pgpt, gpt_header *agpt, uint64_t lastlba)
-{
-       int error_found = 0;
-       if (!pgpt || !agpt)
-               return;
-       if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) {
-               fprintf(stderr,
-                      "GPT:Primary header LBA != Alt. header alternate_lba\n");
-               fprintf(stderr,  "GPT:%" PRIx64 "x != %" PRIx64 "x\n",
-                      le64_to_cpu(pgpt->my_lba),
-                      le64_to_cpu(agpt->alternate_lba));
-               error_found++;
-       }
-       if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) {
-               fprintf(stderr,
-                      "GPT:Primary header alternate_lba != Alt. header my_lba\n");
-               fprintf(stderr,  "GPT:%" PRIx64 " != %" PRIx64 "\n",
-                      le64_to_cpu(pgpt->alternate_lba),
-                      le64_to_cpu(agpt->my_lba));
-               error_found++;
-       }
-       if (le64_to_cpu(pgpt->first_usable_lba) !=
-            le64_to_cpu(agpt->first_usable_lba)) {
-               fprintf(stderr,  "GPT:first_usable_lbas don't match.\n");
-               fprintf(stderr,  "GPT:%" PRIx64 " != %" PRIx64 "\n",
-                      le64_to_cpu(pgpt->first_usable_lba),
-                      le64_to_cpu(agpt->first_usable_lba));
-               error_found++;
-       }
-       if (le64_to_cpu(pgpt->last_usable_lba) !=
-            le64_to_cpu(agpt->last_usable_lba)) {
-               fprintf(stderr,  "GPT:last_usable_lbas don't match.\n");
-               fprintf(stderr,  "GPT:%" PRIx64 " != %" PRIx64 "\n",
-                      le64_to_cpu(pgpt->last_usable_lba),
-                      le64_to_cpu(agpt->last_usable_lba));
-               error_found++;
-       }
-       if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
-               fprintf(stderr,  "GPT:disk_guids don't match.\n");
-               error_found++;
-       }
-       if (le32_to_cpu(pgpt->num_partition_entries) !=
-            le32_to_cpu(agpt->num_partition_entries)) {
-               fprintf(stderr,  "GPT:num_partition_entries don't match: "
-                      "0x%x != 0x%x\n",
-                      le32_to_cpu(pgpt->num_partition_entries),
-                      le32_to_cpu(agpt->num_partition_entries));
-               error_found++;
-       }
-       if (le32_to_cpu(pgpt->sizeof_partition_entry) !=
-            le32_to_cpu(agpt->sizeof_partition_entry)) {
-               fprintf(stderr,
-                      "GPT:sizeof_partition_entry values don't match: "
-                      "0x%x != 0x%x\n",
-                      le32_to_cpu(pgpt->sizeof_partition_entry),
-                      le32_to_cpu(agpt->sizeof_partition_entry));
-               error_found++;
-       }
-       if (le32_to_cpu(pgpt->partition_entry_array_crc32) !=
-            le32_to_cpu(agpt->partition_entry_array_crc32)) {
-               fprintf(stderr,
-                      "GPT:partition_entry_array_crc32 values don't match: "
-                      "0x%x != 0x%x\n",
-                      le32_to_cpu(pgpt->partition_entry_array_crc32),
-                      le32_to_cpu(agpt->partition_entry_array_crc32));
-               error_found++;
-       }
-       if (le64_to_cpu(pgpt->alternate_lba) != lastlba) {
-               fprintf(stderr,
-                      "GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
-               fprintf(stderr,  "GPT:%" PRIx64 " != %" PRIx64 "\n",
-                      le64_to_cpu(pgpt->alternate_lba), lastlba);
-               error_found++;
-       }
-
-       if (le64_to_cpu(agpt->my_lba) != lastlba) {
-               fprintf(stderr,
-                      "GPT:Alternate GPT header not at the end of the disk.\n");
-               fprintf(stderr,  "GPT:%" PRIx64 " != %" PRIx64 "\n",
-                      le64_to_cpu(agpt->my_lba), lastlba);
-               error_found++;
-       }
-
-       if (error_found)
-               fprintf(stderr,
-                      "GPT: Use GNU Parted to correct GPT errors.\n");
-       return;
-}
-
-/**
- * find_valid_gpt() - Search disk for valid GPT headers and PTEs
- * @fd  is an open file descriptor to the whole disk
- * @gpt is a GPT header ptr, filled on return.
- * @ptes is a PTEs ptr, filled on return.
- * Description: Returns 1 if valid, 0 on error.
- * If valid, returns pointers to newly allocated GPT header and PTEs.
- * Validity depends on finding either the Primary GPT header and PTEs valid,
- * or the Alternate GPT header and PTEs valid, and the PMBR valid.
- */
-static int
-find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes)
-{
-        extern int force_gpt;
-       int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
-       gpt_header *pgpt = NULL, *agpt = NULL;
-       gpt_entry *pptes = NULL, *aptes = NULL;
-       legacy_mbr *legacymbr = NULL;
-       uint64_t lastlba;
-       if (!gpt || !ptes)
-               return 0;
-
-       lastlba = last_lba(fd);
-       good_pgpt = is_gpt_valid(fd, GPT_PRIMARY_PARTITION_TABLE_LBA,
-                                &pgpt, &pptes);
-        if (good_pgpt) {
-               good_agpt = is_gpt_valid(fd,
-                                         le64_to_cpu(pgpt->alternate_lba),
-                                        &agpt, &aptes);
-                if (!good_agpt) {
-                        good_agpt = is_gpt_valid(fd, lastlba,
-                                                 &agpt, &aptes);
-                }
-        }
-        else {
-                good_agpt = is_gpt_valid(fd, lastlba,
-                                         &agpt, &aptes);
-        }
-
-        /* The obviously unsuccessful case */
-        if (!good_pgpt && !good_agpt) {
-                goto fail;
-        }
-
-       /* This will be added to the EFI Spec. per Intel after v1.02. */
-        legacymbr = malloc(sizeof (*legacymbr));
-        if (legacymbr) {
-                memset(legacymbr, 0, sizeof (*legacymbr));
-                read_lba(fd, 0, (uint8_t *) legacymbr,
-                         sizeof (*legacymbr));
-                good_pmbr = is_pmbr_valid(legacymbr);
-                free(legacymbr);
-                legacymbr=NULL;
-        }
-
-        /* Failure due to bad PMBR */
-        if ((good_pgpt || good_agpt) && !good_pmbr && !force_gpt) {
-                fprintf(stderr,
-                       "  Warning: Disk has a valid GPT signature "
-                       "but invalid PMBR.\n"
-                       "  Assuming this disk is *not* a GPT disk anymore.\n"
-                       "  Use gpt kernel option to override.  "
-                       "Use GNU Parted to correct disk.\n");
-                goto fail;
-        }
-
-        /* Would fail due to bad PMBR, but force GPT anyhow */
-        if ((good_pgpt || good_agpt) && !good_pmbr && force_gpt) {
-                fprintf(stderr, 
-                       "  Warning: Disk has a valid GPT signature but "
-                       "invalid PMBR.\n"
-                       "  Use GNU Parted to correct disk.\n"
-                       "  gpt option taken, disk treated as GPT.\n");
-        }
-
-        compare_gpts(pgpt, agpt, lastlba);
-
-        /* The good cases */
-        if (good_pgpt && (good_pmbr || force_gpt)) {
-                *gpt  = pgpt;
-                *ptes = pptes;
-                if (agpt)  { free(agpt);   agpt = NULL; }
-                if (aptes) { free(aptes); aptes = NULL; }
-                if (!good_agpt) {
-                        fprintf(stderr, 
-                              "Alternate GPT is invalid, "
-                               "using primary GPT.\n");
-                }
-                return 1;
-        }
-        else if (good_agpt && (good_pmbr || force_gpt)) {
-                *gpt  = agpt;
-                *ptes = aptes;
-                if (pgpt)  { free(pgpt);   pgpt = NULL; }
-                if (pptes) { free(pptes); pptes = NULL; }
-                fprintf(stderr, 
-                       "Primary GPT is invalid, using alternate GPT.\n");
-                return 1;
-        }
-
- fail:
-        if (pgpt)  { free(pgpt);   pgpt=NULL; }
-        if (agpt)  { free(agpt);   agpt=NULL; }
-        if (pptes) { free(pptes); pptes=NULL; }
-        if (aptes) { free(aptes); aptes=NULL; }
-        *gpt = NULL;
-        *ptes = NULL;
-        return 0;
-}
-
-/**
- * read_gpt_pt() 
- * @fd
- * @all - slice with start/size of whole disk
- *
- *  0 if this isn't our partition table
- *  number of partitions if successful
- *
- */
-int
-read_gpt_pt (int fd, struct slice all, struct slice *sp, int ns)
-{
-       gpt_header *gpt = NULL;
-       gpt_entry *ptes = NULL;
-       uint32_t i;
-       int n = 0;
-        int last_used_index=-1;
-
-       if (!find_valid_gpt (fd, &gpt, &ptes) || !gpt || !ptes) {
-               free (gpt);
-               free (ptes);
-               return 0;
-       }
-
-       for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < ns; i++) {
-               if (!efi_guidcmp (NULL_GUID, ptes[i].partition_type_guid)) {
-                       sp[n].start = 0;
-                       sp[n].size = 0;
-                       n++;
-               } else {
-                       sp[n].start = le64_to_cpu(ptes[i].starting_lba);
-                       sp[n].size  = le64_to_cpu(ptes[i].ending_lba) -
-                               le64_to_cpu(ptes[i].starting_lba) + 1;
-                        last_used_index=n;
-                       n++;
-               }
-       }
-       free (ptes);
-       free (gpt);
-       return last_used_index+1;
-}
diff --git a/partx/gpt.h b/partx/gpt.h
deleted file mode 100644 (file)
index 39814b5..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
-    gpt.[ch]
-
-    Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@dell.com> 
-
-    EFI GUID Partition Table handling
-    Per Intel EFI Specification v1.02
-    http://developer.intel.com/technology/efi/efi.htm
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#ifndef _GPT_H
-#define _GPT_H
-
-
-#include <inttypes.h>
-#include "partx.h"
-#include "dos.h"
-#include "efi.h"
-
-#define EFI_PMBR_OSTYPE_EFI 0xEF
-#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
-#define MSDOS_MBR_SIGNATURE 0xaa55
-#define GPT_BLOCK_SIZE 512
-
-#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
-#define GPT_HEADER_REVISION_V1_02 0x00010200
-#define GPT_HEADER_REVISION_V1_00 0x00010000
-#define GPT_HEADER_REVISION_V0_99 0x00009900
-#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
-
-typedef struct _gpt_header {
-       uint64_t signature;
-       uint32_t revision;
-       uint32_t header_size;
-       uint32_t header_crc32;
-       uint32_t reserved1;
-       uint64_t my_lba;
-       uint64_t alternate_lba;
-       uint64_t first_usable_lba;
-       uint64_t last_usable_lba;
-       efi_guid_t disk_guid;
-       uint64_t partition_entry_lba;
-       uint32_t num_partition_entries;
-       uint32_t sizeof_partition_entry;
-       uint32_t partition_entry_array_crc32;
-       uint8_t reserved2[GPT_BLOCK_SIZE - 92];
-} __attribute__ ((packed)) gpt_header;
-
-typedef struct _gpt_entry_attributes {
-       uint64_t required_to_function:1;
-       uint64_t reserved:47;
-        uint64_t type_guid_specific:16;
-} __attribute__ ((packed)) gpt_entry_attributes;
-
-typedef struct _gpt_entry {
-       efi_guid_t partition_type_guid;
-       efi_guid_t unique_partition_guid;
-       uint64_t starting_lba;
-       uint64_t ending_lba;
-       gpt_entry_attributes attributes;
-       efi_char16_t partition_name[72 / sizeof(efi_char16_t)];
-} __attribute__ ((packed)) gpt_entry;
-
-
-/* 
-   These values are only defaults.  The actual on-disk structures
-   may define different sizes, so use those unless creating a new GPT disk!
-*/
-
-#define GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE 16384
-/* 
-   Number of actual partition entries should be calculated
-   as: 
-*/
-#define GPT_DEFAULT_RESERVED_PARTITION_ENTRIES \
-        (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE / \
-         sizeof(gpt_entry))
-
-
-/* Protected Master Boot Record  & Legacy MBR share same structure */
-/* Needs to be packed because the u16s force misalignment. */
-
-typedef struct _legacy_mbr {
-       uint8_t bootcode[440];
-       uint32_t unique_mbr_signature;
-       uint16_t unknown;
-       struct partition partition[4];
-       uint16_t signature;
-} __attribute__ ((packed)) legacy_mbr;
-
-
-#define EFI_GPT_PRIMARY_PARTITION_TABLE_LBA 1
-
-/* Functions */
-int read_gpt_pt (int fd, struct slice all, struct slice *sp, int ns);
-
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff --git a/partx/mac.c b/partx/mac.c
deleted file mode 100644 (file)
index 11de6bd..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Lifted from kpartx's mac.c
- *
- * Integrated to partx
- *       Davidlohr Bueso <dave@gnu.org>
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-
-#include "bitops.h"
-#include "partx.h"
-
-#define MAC_PARTITION_MAGIC     0x504d
-#define MAC_DRIVER_MAGIC        0x4552
-
-struct mac_partition {
-        uint16_t  signature;      /* expected to be MAC_PARTITION_MAGIC */
-        uint16_t  res1;
-        uint32_t  map_count;      /* # blocks in partition map */
-        uint32_t  start_block;    /* absolute starting block # of partition */
-        uint32_t  block_count;    /* number of blocks in partition */
-        /* there is more stuff after this that we don't need */
-};
-
-/* Driver descriptor structure, in block 0 */
-struct mac_driver_desc {
-        uint16_t  signature;      /* expected to be MAC_DRIVER_MAGIC */
-        uint16_t  block_size;
-        uint32_t  block_count;
-};
-
-int
-read_mac_pt(int fd, struct slice all, struct slice *sp, int ns) {
-       struct mac_driver_desc *md;
-        struct mac_partition *part;
-       unsigned secsize;
-       unsigned char *data;
-       int blk, blocks_in_map;
-        int n = 0;
-
-       md = (struct mac_driver_desc *) getblock(fd, 0);
-       if (md == NULL)
-               return -1;
-
-       if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC)
-               return -1;
-
-       secsize = be16_to_cpu(md->block_size);
-       data = getblock(fd, secsize/512);
-       if (!data)
-               return -1;
-       part = (struct mac_partition *) (data + secsize%512);
-
-       if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
-               return -1;
-
-       blocks_in_map = be32_to_cpu(part->map_count);
-       for (blk = 1; blk <= blocks_in_map && blk <= ns; ++blk, ++n) {
-               int pos = blk * secsize;
-               data = getblock(fd, pos/512);
-               if (!data)
-                       return -1;
-
-               part = (struct mac_partition *) (data + pos%512);
-               if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
-                       break;
-
-               sp[n].start = be32_to_cpu(part->start_block) * (secsize/512);
-               sp[n].size = be32_to_cpu(part->block_count) * (secsize/512);
-       }
-       return n;
-}
index b24bc87bbe752977d722a379615be35a1ea61333..efd7dbd5b1bde9e2d86c3611f4911a288d5bc421 100644 (file)
 .\" partx.8 --
 .\" Copyright 2007 Karel Zak <kzak@redhat.com>
 .\" Copyright 2007 Red Hat, Inc.
+.\" Copyright 2010 Davidlohr Bueso <dave@gnu.org>
 .\" May be distributed under the GNU General Public License
-.TH PARTX 8 "11 Jan 2007"
+.TH PARTX 8 "28 Oct 2010"
 .SH NAME
 partx \-
-telling the kernel about presence and numbering of on-disk partitions.
+tell the linux kernel about presence and numbering of on-disk partitions.
 .SH SYNOPSIS
 .B partx
-.RB [ \-a | \-d | \-l ]
-.RB [ \-\-type
+.RB [ \-a | \-d | \-s ]
+.RB [ \-t
 .IR TYPE ]
-.RB [ \-\-nr
-.IR M-N ]
-.RI [ partition ]
+.RB [ \-n
+.IR M:N ]
+.RI [ \- ]
 .I disk
+
+.B partx
+.RB [ \-a | \-d | \-s ]
+.RB [ \-t
+.IR TYPE ]
+.I partition
+.RI [ disk ]
+
 .SH DESCRIPTION
-Given a block device (
-.B disk
-) and a partition table
-.B type
-, try to parse the partition table, and list the
+Given a device or disk-image, try to parse the partition table, and list the
 contents. Optionally add or remove partitions.
 
-This is not an fdisk - adding and removing partitions
+The
+.I disk
+argument is optional when a 
+.I partition 
+argument is provided. It's possible to force scannig on partition (for example
+to list nested subpartitions), then the string "-" has to be used, for example:
+
+.RS
+.br
+.B partx \-\-show \- /dev/sda3
+.RE
+
+This will use sda3 as a whole-disk rather than a partition.
+
+.B 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.
 
 .SH OPTIONS
-.TP
-.B \-a
+.IP "\fB\-a, \-\-add\fP"
 add specified partitions or read disk and add all partitions
-.TP
-.B \-d
+.IP "\fB\-b, \-\-bytes\fP"
+Print the SIZE column in bytes rather than in human readable format.
+.IP "\fB\-d, \-\-delete\fP"
 delete specified or all partitions
+.IP "\fB\-l, \-\-list\fP"
+list partitions. Note that the all numbers are in 512-byte sectors. This output
+format is DEPRECATED in favour of \fB\-\-show\fP. Don't use it in newly written
+scripts.
+.IP "\fB\-g, \-\-noheadings\fP"
+Do not print a header line.
+.IP "\fB\-o, \-\-output \fIlist\fP"
+Define output columns for \fB\-\-show\fP and  \fB\-\-raw\fP output. If output format is
+not specified then \fB\-\-show\fP is enable by default. Use \fB\-\-help\fP to 
+get list of all supported columns.
+.IP "\fB\-r, \-\-raw\fP"
+Use raw output format.
+.IP "\fB\-s, \-\-show\fP"
+list partitions. All numbers (except SIZE) are in 512-byte sectors. The output
+columns could be (re)defined by \fB\-\-output\fP option.
+.IP "\fB\-t, \-\-type \fItype\fP"
+Specify the partition table type -- dos, bsd, solaris, unixware or gpt.
+.IP "\fB\-n, \-\-nr \fIM:N\fP"
+Specify the range of partitions. For backward compatibility is also supported
+range definition in <M-N> format. The range could be specified by negative 
+numbers, for example "--nr :-1" means last partition, and "--nr -2:-1" means 
+last two partition. Supported range specifications:
+.RS
 .TP
-.B \-l
-list partitions. Note that the all numbers are in 512-byte sectors.
+.B <M>
+Specify only one partition (e.g. --nr 3).
 .TP
-.BI --type " TYPE"
-Specify the partition type -- dos, bsd, solaris, unixware or gpt.
+.B <M:>
+Specify lower limit only (e.g. --nr 2:).
 .TP
-.BI --nr " M-N"
-Specify the range of partitions (e.g --nr 2-4).
+.B <:N>
+Specify upper limit only (e.g. --nr :4).
+.TP
+.B <M:N>
+or
+.B <M-N>
+Specify lower and upper limits (e.g. --nr 2:4).
+.RE
+.SH EXAMPLES
+.IP "\fBpartx \-\-show /dev/sdb3\fP"
+.IP "\fBpartx \-\-show --nr 3 /dev/sdb\fP"
+.IP "\fBpartx \-\-show /dev/sdb3 /dev/sdb\fP"
+List partition 3 of /dev/sdb.
+.IP "\fBpartx \-\-show \- /dev/sdb3\fP"
+List all subpartitions on /dev/sdb3 (the device is used as whole-disk).
+.IP "\fBpartx \-o START -g --nr 3 /dev/sdb\fP"
+Print the start sector of partition 5 on /dev/sda without header.
+.IP "\fBpartx \-o SECTORS,SIZE /dev/sda5 /dev/sda\fP"
+List the length in sectors and human readable size of partition 5 on /dev/sda.
+.IP "\fBpartx \-\-add --nr 3:5 /dev/sdd\fP"
+Add all available partitions from 3 to 5 (inclusive) on /dev/sdd.
+.IP "\fBpartx \-d --nr :-1 /dev/sdd\fP"
+Removes last partition on /dev/sdd.
 
 .SH SEE ALSO
 .BR addpart (8),
@@ -51,6 +115,13 @@ Specify the range of partitions (e.g --nr 2-4).
 .BR parted (8),
 .BR partprobe (8)
 
+.SH SEE ALSO
+.nf
+Davidlohr Bueso <dave@gnu.org>
+Karel Zak <kzak@redhat.com>
+.fi
+
+The original version was written by Andries E. Brouwer <aeb@cwi.nl>.
 .SH AVAILABILITY
 The partx command is part of the util-linux package and is available from
 ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
index aa5a2ad8fd2c27f173e2af7700ba814cf0cccb96..e0f1f2a9b3e59d675a9be2296c39ea903718db86 100644 (file)
 /*
- * 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;
 }
+
index 8702f2593641cdf62c0c475536d89d2e969f3b98..b40fa8fbd93c6be975edb9227c6b39cf6679bb99 100644 (file)
@@ -1,32 +1,44 @@
-#ifndef PARTX_H_INCLUDED
-#define PARTX_H_INCLUDED
-
-/*
- * For each partition type there is a routine that takes
- * a block device and a range, and returns the list of
- * slices found there in the supplied array SP that can
- * hold NS entries. The return value is the number of
- * entries stored, or -1 if the appropriate type is not
- * present.
- */
-
-
-/* units: 512 byte sectors */
-struct slice {
-       unsigned int start;
-       unsigned int size;
-};
-
-typedef int (ptreader)(int fd, struct slice all, struct slice *sp, int ns);
-
-extern ptreader read_dos_pt, read_bsd_pt, read_solaris_pt, read_unixware_pt, read_gpt_pt;
-extern ptreader read_sun_pt, read_mac_pt;
-
-unsigned char *getblock(int fd, unsigned int secnr);
+#ifndef UTIL_LINUX_PARTX_H
+#define UTIL_LINUX_PARTX_H
+
+#include <sys/ioctl.h>
+#include <linux/blkpg.h>
+
+static inline int partx_del_partition(int fd, int partno)
+{
+       struct blkpg_ioctl_arg a;
+       struct blkpg_partition p;
+
+       p.pno = partno;
+       p.start = 0;
+       p.length = 0;
+       p.devname[0] = 0;
+       p.volname[0] = 0;
+       a.op = BLKPG_DEL_PARTITION;
+       a.flags = 0;
+       a.datalen = sizeof(p);
+       a.data = &p;
+
+       return ioctl(fd, BLKPG, &a);
+}
 
-static inline int
-four2int(unsigned char *p) {
-       return p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24);
+static inline int partx_add_partition(int fd, int partno,
+                       unsigned long start, unsigned long size)
+{
+       struct blkpg_ioctl_arg a;
+       struct blkpg_partition p;
+
+       p.pno = partno;
+       p.start = start << 9;
+       p.length = size << 9;
+       p.devname[0] = 0;
+       p.volname[0] = 0;
+       a.op = BLKPG_ADD_PARTITION;
+       a.flags = 0;
+       a.datalen = sizeof(p);
+       a.data = &p;
+
+       return ioctl(fd, BLKPG, &a);
 }
 
-#endif /* PARTX_H_INCLUDED */
+#endif /*  UTIL_LINUX_PARTX_H */
diff --git a/partx/solaris.c b/partx/solaris.c
deleted file mode 100644 (file)
index 24075ae..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#include <stdio.h>
-#include <time.h>              /* time_t */
-#include <sys/types.h>
-#include "partx.h"
-
-#define SOLARIS_X86_NUMSLICE   8
-#define SOLARIS_X86_VTOC_SANE  (0x600DDEEEUL)
-
-struct solaris_x86_slice {
-       unsigned short  s_tag;          /* ID tag of partition */
-       unsigned short  s_flag;         /* permision flags */
-       daddr_t         s_start;        /* start sector no of partition */
-       long            s_size;         /* # of blocks in partition */
-};
-
-struct solaris_x86_vtoc {
-       unsigned long v_bootinfo[3];    /* info for mboot */
-       unsigned long v_sanity;         /* to verify vtoc sanity */
-       unsigned long v_version;        /* layout version */
-       char    v_volume[8];            /* volume name */
-       unsigned short  v_sectorsz;     /* sector size in bytes */
-       unsigned short  v_nparts;       /* number of partitions */
-       unsigned long v_reserved[10];   /* free space */
-       struct solaris_x86_slice
-               v_slice[SOLARIS_X86_NUMSLICE];   /* slice headers */
-       time_t  timestamp[SOLARIS_X86_NUMSLICE]; /* timestamp */
-       char    v_asciilabel[128];      /* for compatibility */
-};
-
-int
-read_solaris_pt(int fd, struct slice all, struct slice *sp, int ns) {
-       struct solaris_x86_vtoc *v;
-       struct solaris_x86_slice *s;
-       unsigned int offset = all.start;
-       int i, n;
-       unsigned char *bp;
-
-       bp = getblock(fd, offset+1);    /* 1 sector suffices */
-       if (bp == NULL)
-               return -1;
-
-       v = (struct solaris_x86_vtoc *) bp;
-       if(v->v_sanity != SOLARIS_X86_VTOC_SANE)
-               return -1;
-
-       if(v->v_version != 1) {
-               fprintf(stderr, "Cannot handle solaris version %ld vtoc\n",
-                      v->v_version);
-               return 0;
-       }
-
-       for(i=0, n=0; i<SOLARIS_X86_NUMSLICE; i++) {
-               s = &v->v_slice[i];
-
-               if (s->s_size == 0)
-                       continue;
-               if (n < ns) {
-                       sp[n].start = offset + s->s_start;
-                       sp[n].size = s->s_size;
-                       n++;
-               } else {
-                       fprintf(stderr,
-                               "solaris_x86_partition: too many slices\n");
-                       break;
-               }
-       }
-       return n;
-}
-
diff --git a/partx/sun.c b/partx/sun.c
deleted file mode 100644 (file)
index 5bfe2ad..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Lifted from kpartx's sun.c
- *
- * Copyrights of the original file apply
- * Copyright (c) 2007 Hannes Reinecke
- *
- * Integrated to partx
- *       Davidlohr Bueso <dave@gnu.org>
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-
-#include "bitops.h"
-#include "partx.h"
-
-#define SUN_DISK_MAGIC         0xDABE  /* Disk magic number */
-#define SUN_DISK_MAXPARTITIONS 8
-
-struct __attribute__ ((packed)) sun_raw_part {
-       u_int32_t       start_cylinder; /* where the part starts... */
-       u_int32_t       num_sectors;    /* ...and it's length */
-};
-
-struct __attribute__ ((packed)) sun_part_info {
-       u_int8_t        spare1;
-       u_int8_t        id;             /* Partition type */
-       u_int8_t        spare2;
-       u_int8_t        flags;          /* Partition flags */
-};
-
-struct __attribute__ ((packed)) sun_disk_label {
-       char            info[128];      /* Informative text string */
-       u_int8_t        spare0[14];
-       struct sun_part_info infos[SUN_DISK_MAXPARTITIONS];
-       u_int8_t        spare1[246];    /* Boot information etc. */
-       u_int16_t       rspeed;         /* Disk rotational speed */
-       u_int16_t       pcylcount;      /* Physical cylinder count */
-       u_int16_t       sparecyl;       /* extra sects per cylinder */
-       u_int8_t        spare2[4];      /* More magic... */
-       u_int16_t       ilfact;         /* Interleave factor */
-       u_int16_t       ncyl;           /* Data cylinder count */
-       u_int16_t       nacyl;          /* Alt. cylinder count */
-       u_int16_t       ntrks;          /* Tracks per cylinder */
-       u_int16_t       nsect;          /* Sectors per track */
-       u_int8_t        spare3[4];      /* Even more magic... */
-       struct sun_raw_part partitions[SUN_DISK_MAXPARTITIONS];
-       u_int16_t       magic;          /* Magic number */
-       u_int16_t       csum;           /* Label xor'd checksum */
-};
-
-/* Checksum Verification */
-static int
-sun_verify_checksum (struct sun_disk_label *label)
-{
-       u_int16_t *ush = ((u_int16_t *)(label + 1)) - 1;
-       u_int16_t csum = 0;
-
-       while (ush >= (u_int16_t *)label)
-               csum ^= *ush--;
-
-       return !csum;
-}
-
-int
-read_sun_pt(int fd, struct slice all, struct slice *sp, int ns) {
-       struct sun_disk_label *l;
-       struct sun_raw_part *s;
-       unsigned int offset = all.start, end;
-       int i, j, n;
-       unsigned char *bp;
-
-       bp = getblock(fd, offset);
-       if (bp == NULL)
-               return -1;
-
-       l = (struct sun_disk_label *) bp;
-       if(be16_to_cpu(l->magic) != SUN_DISK_MAGIC)
-               return -1;
-
-       if (!sun_verify_checksum(l)) {
-               fprintf(stderr, "Corrupted Sun disk label\n");
-               return -1;
-       }
-
-       for(i=0, n=0; i<SUN_DISK_MAXPARTITIONS; i++) {
-               s = &l->partitions[i];
-
-               if (s->num_sectors == 0)
-                       continue;
-               if (n < ns) {
-                       sp[n].start = offset +
-                               be32_to_cpu(s->start_cylinder) * be16_to_cpu(l->nsect) * be16_to_cpu(l->ntrks);
-                       sp[n].size = be32_to_cpu(s->num_sectors);
-                       n++;
-               } else {
-                       fprintf(stderr,
-                               "sun_disklabel: too many slices\n");
-                       break;
-               }
-       }
-       /*
-        * Convention has it that the SUN disklabel will always have
-        * the 'c' partition spanning the entire disk.
-        * So we have to check for contained slices.
-        */
-       for(i = 0; i < SUN_DISK_MAXPARTITIONS; i++) {
-               if (sp[i].size == 0)
-                       continue;
-
-               end = sp[i].start + sp[i].size;
-               for(j = 0; j < SUN_DISK_MAXPARTITIONS; j ++) {
-                       if ( i == j )
-                               continue;
-                       if (sp[j].size == 0)
-                               continue;
-
-                       if (sp[i].start < sp[j].start) {
-                               if (end > sp[j].start &&
-                                   end < sp[j].start + sp[j].size) {
-                                       /* Invalid slice */
-                                       fprintf(stderr,
-                                               "sun_disklabel: slice %d overlaps with %d\n", i , j);
-                                       sp[i].size = 0;
-                               }
-                       }
-               }
-       }
-       return n;
-}
diff --git a/partx/unixware.c b/partx/unixware.c
deleted file mode 100644 (file)
index c131475..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-#include <stdio.h>
-#include "partx.h"
-
-#define UNIXWARE_FS_UNUSED     0
-#define UNIXWARE_NUMSLICE      16
-#define UNIXWARE_DISKMAGIC     (0xCA5E600D)
-#define UNIXWARE_DISKMAGIC2    (0x600DDEEE)
-
-struct unixware_slice {
-       unsigned short s_label;         /* label */
-       unsigned short s_flags;         /* permission flags */
-       unsigned int   start_sect;      /* starting sector */
-       unsigned int   nr_sects;        /* number of sectors in slice */
-};
-
-struct unixware_disklabel {
-       unsigned int   d_type;          /* drive type */
-       unsigned char  d_magic[4];      /* the magic number */
-       unsigned int   d_version;       /* version number */
-       char    d_serial[12];           /* serial number of the device */
-       unsigned int   d_ncylinders;    /* # of data cylinders per device */
-       unsigned int   d_ntracks;       /* # of tracks per cylinder */
-       unsigned int   d_nsectors;      /* # of data sectors per track */
-       unsigned int   d_secsize;       /* # of bytes per sector */
-       unsigned int   d_part_start;    /* # of first sector of this partition */
-       unsigned int   d_unknown1[12];  /* ? */
-       unsigned int   d_alt_tbl;       /* byte offset of alternate table */
-       unsigned int   d_alt_len;       /* byte length of alternate table */
-       unsigned int   d_phys_cyl;      /* # of physical cylinders per device */
-       unsigned int   d_phys_trk;      /* # of physical tracks per cylinder */
-       unsigned int   d_phys_sec;      /* # of physical sectors per track */
-       unsigned int   d_phys_bytes;    /* # of physical bytes per sector */
-       unsigned int   d_unknown2;      /* ? */
-       unsigned int   d_unknown3;      /* ? */
-       unsigned int   d_pad[8];        /* pad */
-
-       struct unixware_vtoc {
-               unsigned char   v_magic[4];     /* the magic number */
-               unsigned int    v_version;      /* version number */
-               char    v_name[8];              /* volume name */
-               unsigned short  v_nslices;      /* # of slices */
-               unsigned short  v_unknown1;     /* ? */
-               unsigned int    v_reserved[10]; /* reserved */
-               struct unixware_slice
-                   v_slice[UNIXWARE_NUMSLICE]; /* slice headers */
-       } vtoc;
-
-};  /* 408 */
-
-int
-read_unixware_pt(int fd, struct slice all, struct slice *sp, int ns) {
-       struct unixware_disklabel *l;
-       struct unixware_slice *p;
-       unsigned int offset = all.start;
-       unsigned char *bp;
-       int n = 0;
-
-       bp = getblock(fd, offset+29);   /* 1 sector suffices */
-       if (bp == NULL)
-               return -1;
-
-       l = (struct unixware_disklabel *) bp;
-       if (four2int(l->d_magic) != UNIXWARE_DISKMAGIC ||
-           four2int(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2)
-               return -1;
-
-       p = &l->vtoc.v_slice[1];        /* slice 0 is the whole disk. */
-       while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
-               if (p->s_label == UNIXWARE_FS_UNUSED)
-                       /* nothing */;
-               else if (n < ns) {
-                       sp[n].start = p->start_sect;
-                       sp[n].size = p->nr_sects;
-                       n++;
-               } else {
-                       fprintf(stderr,
-                               "unixware_partition: too many slices\n");
-                       break;
-               }
-               p++;
-       }
-       return n;
-}