From: Davidlohr Bueso <dave@xxxxxxx> Enhancements: * Use libblkid * Usable for for both real devices and regular files (images) * Control output by PARTNO, START, LENGTH, SECTORS SIZE, NAME and/or UUID * Interpret partition tables the same way the kernel does, empty ones are ignored * Translate partition name to whole disks * Keep backwards compatibility Signed-off-by: Davidlohr Bueso <dave@xxxxxxx> --- partx/Makefile.am | 15 +- partx/bsd.c | 83 ----- partx/crc32.c | 393 ----------------------- partx/crc32.h | 19 -- partx/dos.c | 138 -------- partx/dos.h | 13 - partx/efi.h | 57 ---- partx/gpt.c | 510 ------------------------------ partx/gpt.h | 131 -------- partx/mac.c | 74 ----- partx/partx.8 | 40 ++- partx/partx.c | 905 +++++++++++++++++++++++++++++++++-------------------- partx/partx.h | 32 -- partx/solaris.c | 69 ---- partx/sun.c | 130 -------- partx/unixware.c | 83 ----- 16 files changed, 619 insertions(+), 2073 deletions(-) delete mode 100644 partx/bsd.c delete mode 100644 partx/crc32.c delete mode 100644 partx/crc32.h delete mode 100644 partx/dos.c delete mode 100644 partx/dos.h delete mode 100644 partx/efi.h delete mode 100644 partx/gpt.c delete mode 100644 partx/gpt.h delete mode 100644 partx/mac.c delete mode 100644 partx/partx.h delete mode 100644 partx/solaris.c delete mode 100644 partx/sun.c delete mode 100644 partx/unixware.c diff --git a/partx/Makefile.am b/partx/Makefile.am index a26963e..eea8ee8 100644 --- a/partx/Makefile.am +++ b/partx/Makefile.am @@ -3,13 +3,24 @@ include $(top_srcdir)/config/include-Makefile.am if BUILD_PARTX 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 +partx_SOURCES = partx.c $(top_srcdir)/lib/blkdev.c $(top_srcdir)/lib/tt.c if LINUX partx_SOURCES += $(top_srcdir)/lib/linux_version.c endif +cflags_blkid = $(AM_CFLAGS) +ldadd_blkid = + +if BUILD_LIBBLKID +# only in-tree libblkid has topology support +ldadd_blkid += $(ul_libblkid_la) +cflags_blkid += -I$(ul_libblkid_incdir) +endif + +partx_CFLAGS = $(cflags_blkid) +partx_LDADD = $(ldadd_blkid) + dist_man_MANS = addpart.8 delpart.8 partx.8 endif diff --git a/partx/bsd.c b/partx/bsd.c deleted file mode 100644 index 4532c32..0000000 --- a/partx/bsd.c +++ /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 index 4120f72..0000000 --- a/partx/crc32.c +++ /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 index a4505b8..0000000 --- a/partx/crc32.h +++ /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 index f962f37..0000000 --- a/partx/dos.c +++ /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 index 877beec..0000000 --- a/partx/dos.h +++ /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 index fcf2740..0000000 --- a/partx/efi.h +++ /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@xxxxxxxx> - - 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 index be612fc..0000000 --- a/partx/gpt.c +++ /dev/null @@ -1,510 +0,0 @@ -/* - gpt.[ch] - - Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@xxxxxxxx> - - 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, §or_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 index 39814b5..0000000 --- a/partx/gpt.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - gpt.[ch] - - Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@xxxxxxxx> - - 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 index a5677f0..0000000 --- a/partx/mac.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Lifted from kpartx's mac.c - * - * Integrated to partx (utils-linux-ng) - * Davidlohr Bueso <dave@xxxxxxx> - */ - -#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; -} diff --git a/partx/partx.8 b/partx/partx.8 index c6d04c8..41270b7 100644 --- a/partx/partx.8 +++ b/partx/partx.8 @@ -1,11 +1,12 @@ .\" partx.8 -- .\" Copyright 2007 Karel Zak <kzak@xxxxxxxxxx> .\" Copyright 2007 Red Hat, Inc. +.\" Copyright 2010 Davidlohr Bueso <dave@xxxxxxx> .\" 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 ] @@ -15,12 +16,19 @@ telling the kernel about presence and numbering of on-disk partitions. .IR M-N ] .RI [ partition ] .I disk + +.B partx +.RB [ \-a | \-d | \-l ] +.RB [ \-\-type +.IR TYPE ] +.RB [ \-\-nr +.IR M-N ] +.RI partition +.I [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 (partition and/or disk) 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 @@ -38,12 +46,27 @@ delete specified or all partitions .B \-l list partitions. Note that the all numbers are in 512-byte sectors. .TP +.B \-s +list partitions in a new format, adding name and UUID (if applicable). All numbers are in 512-byte sectors. +.TP .BI --type " TYPE" Specify the partition type -- dos, bsd, solaris, unixware or gpt. .TP .BI --nr " M-N" Specify the range of partitions (e.g --nr 2-4). +.SH EXAMPLES +.IP "\fBpartx \-\-list /dev/sdb3\fP" +List partition 3 of /dev/sdb +.IP "\fBpartx \-\-list /dev/sda\fP" +Lists all partitions on /dev/sda +.IP "\fBpartx \-\-list \-o LENGTH,SIZE /dev/sda5 /dev/sda\fP" +List the length and size of partition 5 on /dev/sda +.IP "\fBpartx \-\-add --nr 3-5 /dev/sdd\fP" +Adds all available partitions from 3 to 5 (inclusive) on /dev/sdd +.IP "\fBpartx \-d /dev/sdd\fP" +Removes all available partitions on /dev/sdd + .SH SEE ALSO .BR addpart (8), .BR delpart (8), @@ -51,6 +74,9 @@ Specify the range of partitions (e.g --nr 2-4). .BR parted (8), .BR partprobe (8) +.SH SEE ALSO +The partx command was completely rewritten by Davidlohr Bueso <dave@xxxxxxx> + .SH AVAILABILITY The partx command is part of the util-linux-ng package and is available from ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/. diff --git a/partx/partx.c b/partx/partx.c index aa5a2ad..f7e9387 100644 --- a/partx/partx.c +++ b/partx/partx.c @@ -1,404 +1,645 @@ /* - * 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@xxxxxxx> + * Rewritten to use libblkid for util-linux-ng + * based on ideas from Karel Zak <kzak@xxxxxxxxxx> */ #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 */ +#include <linux/blkpg.h> #ifdef HAVE_LINUX_COMPILER_H #include <linux/compiler.h> #endif -#include <linux/blkpg.h> -#include "c.h" +#include <blkid.h> + +#include "nls.h" +#include "tt.h" #include "blkdev.h" -#include "partx.h" -#include "crc32.h" -static void errmerge(int err, int m, char *msg1, char *msg2); +#define noret __attribute__((__noreturn__)) + +/* all units in byte sectors */ +#define BSECTORS 512 + +/* all the columns (-o option) */ +enum { + COL_PARTNO, + COL_START, + COL_LENGTH, + COL_SECTORS, + COL_SIZE, + COL_NAME, + COL_UUID, + __NCOLUMNS +}; + +enum { + OLDFMT, + NEWFMT, +}; + +/* column names */ +struct colinfo { + const char *name; + double whint; + int truncate; +}; + +/* columns descriptions */ +struct colinfo infos[__NCOLUMNS] = { + [COL_PARTNO] = { "PART", 0.25, 1 }, + [COL_START] = { "START", 0.30, 1 }, + [COL_LENGTH] = { "LENGTH", 0.30, 1 }, + [COL_SECTORS] = { "SECTORS", 0.30, 1 }, + [COL_SIZE] = { "SIZE", 0.30, 1 }, + [COL_NAME] = { "NAME", 0.30, 1 }, + [COL_UUID] = { "UUID", 0.30, 1 }, +}; +/* array with IDs of enabled columns */ +static int columns[__NCOLUMNS], ncolumns = 0; + +/* when passed --nr N-M, lower=N, upper=M */ +static int lower, upper; + +/* + * determine the listing format to be used + * mainly to maintain backwards compatibility +*/ +int outfmt; + +/* + * used if only the partition is passed + * ie: partx /dev/sda1 (partnumber=1) + * partx /dev/sdd4 /dev/sdd (partnumber=4) + */ +static int partnumber = -1; -#define MAXTYPES 64 -#define MAXSLICES 256 +static int verbose = 0; -struct slice slices[MAXSLICES]; +static int get_column_id(int num) +{ + assert(num < ncolumns); + assert(columns[num] < __NCOLUMNS); + return columns[num]; +} + +static struct colinfo *get_column_info(int num) +{ + return &infos[ get_column_id(num) ]; +} + +static const char *get_column_name(int num) +{ + return get_column_info(num)->name; +} -enum action { LIST, ADD, DELETE }; +static float get_column_whint(int num) +{ + return get_column_info(num)->whint; +} -struct pt { - char *type; - ptreader *fn; -} pts[MAXTYPES]; -int ptct; +static const char *column_id_to_name(int id) +{ + assert(id < __NCOLUMNS); + return infos[id].name; +} -static void -addpts(char *t, ptreader f) +/* + * converts @name to column ID + */ +static int column_name_to_id(const char *name, size_t namesz) { - if (ptct >= MAXTYPES) { - fprintf(stderr, "addpts: too many types\n"); - exit(1); + int i; + + for (i = 0; i < __NCOLUMNS; i++) { + const char *cn = column_id_to_name(i); + + if (!strncasecmp(name, cn, namesz) && !*(cn + namesz)) + return i; } - pts[ptct].type = t; - pts[ptct].fn = f; - ptct++; + warnx(_("unknown column: %s"), name); + return -1; } -static void -initpts(void) +/* + * parses list of columns from @str and add IDs to columns[] + */ +static int set_columns(const char *str) { - 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); + const char *begin = NULL, *p; + + ncolumns = 0; + + if (!str || !*str) + return -1; + + ncolumns = 0; + + for (p = str; p && *p; p++) { + const char *end = NULL; + int id; + + if (!begin) + begin = p; /* begin of the column name */ + if (*p == ',') + end = p; /* terminate the name */ + if (*(p + 1) == '\0') + end = p + 1; /* end of string */ + if (!begin || !end) + continue; + if (end <= begin) + return -1; + + id = column_name_to_id(begin, end - begin); + if (id == -1) + return -1; + columns[ncolumns++] = id; + begin = NULL; + if (end && !*end) + break; + } + return 0; } -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 } -}; -/* 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(); +static int noret errx_mutually_exclusive(const char *opts) +{ + errx(EXIT_FAILURE, "%s %s", opts, _("options are mutually exclusive")); +} - 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); +/* + * given a partition return the corresponding partition number. Returns -1 on error. + * Note that this function assumes that the last characters are + * always numeric (sda1, sdc20, etc). + */ +static int get_partno_from_device(char *partition) +{ + int num = -1, i=0, j=0; + char *str = malloc(sizeof(char) * strlen(partition)); + + if (!isdigit(partition[strlen(partition) - 1])) { + free(str); + return num; } - 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; partition[i] != '\0'; i++) { + if (!isdigit(partition[i])) + continue; + else + str[j++] = partition[i]; } - fd = open(diskdevice, O_RDONLY); - if (fd == -1) { - perror(diskdevice); - exit(1); + num = strtol(str, (char **) NULL, 10); + + free(str); + return num; +} + +static char *show_errhelper(void) +{ + /* + * append more useful information + * as to why the error occured + */ + switch (errno) { + case EBUSY: + return "(mounted partition?)"; + case ENXIO: + return "(no such non-empty partition)"; + case EACCES: + case EPERM: + return "(permission denied)"; + default: + return NULL; } +} - /* 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); - } +static void do_add(int fd, int partno, unsigned long start, unsigned long size) +{ + struct blkpg_ioctl_arg a; + struct blkpg_partition pt; + + pt.pno = partno; + pt.start = BSECTORS * start; + pt.length = BSECTORS * size; + pt.devname[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) + fprintf(stderr, "error adding partition #%d %s\n", + partno, show_errhelper()); + else if (verbose) + printf("added partition #%d\n", partno); +} - if (!lower) - lower = 1; - - while (upper == 0 || lower <= upper) { - int 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; +static void add_part(int fd, blkid_partlist ls) +{ + + int i, j, nparts; + + nparts = blkid_partlist_numof_partitions(ls); + if (!nparts) + return; + + for (i = 0; i < nparts; i++) { + blkid_partition par = blkid_partlist_get_partition(ls, i); + unsigned long long start = blkid_partition_get_start(par); + unsigned long long size = blkid_partition_get_size(par); + int partno = blkid_partition_get_partno(par); + + /* skip unwanted partition numbers, if any */ + if (lower && upper) + if (partno < lower || partno > upper) + continue; + if (partnumber != -1) + if (partnumber != partno) + continue; + + /* + * test for overlap, as in the case of an + * extended partition, and reduce size + */ + for (j=i+1; j <= nparts; j++) { + blkid_partition par2 = blkid_partlist_get_partition(ls, j); + unsigned long long start2 = blkid_partition_get_start(par2); + + if (start2 > start && start2 < start + size) { + size = start2 - start; + if (verbose) + printf("reduced size of partition #%d to %llu\n", + partno, size); } - 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; + + do_add(fd, partno, start, size); } +} - if (device != diskdevice) { - fd2 = open(device, O_RDONLY); - if (fd2 == -1) { - perror(device); - exit(1); - } - } else { - fd2 = fd; +static void del_part(int fd, blkid_partlist ls) +{ + struct blkpg_ioctl_arg a; + struct blkpg_partition pt; + int i, nparts = blkid_partlist_numof_partitions(ls); + if (!nparts) + return; + + for (i = 0; i < nparts; i++) { + blkid_partition par = blkid_partlist_get_partition(ls, i); + unsigned long long start = blkid_partition_get_start(par); + unsigned long long size = blkid_partition_get_size(par); + int partno = blkid_partition_get_partno(par); + + /* skip unwanted partition numbers, if any */ + if (lower && upper) + if (partno < lower || partno > upper) + continue; + if (partnumber != -1) + if (partnumber != partno) + continue; + + pt.pno = partno; + pt.start = start; + pt.length = start + size - 1; + pt.devname[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) + fprintf(stderr, "error deleting #partition %d - %s\n", + partno, show_errhelper()); + else if (verbose) + printf("deleted partition #%d\n", partno); } +} + +/* format data and add it as a whole column, for later printing the table */ +static void add_line(struct tt *tt, int partno, unsigned long long start, + unsigned long long size, const char *name, const char *uuid) +{ + int i, rc = -1; + char *str = NULL; - if (ioctl(fd, HDIO_GETGEO, &g)) { - perror("HDIO_GETGEO"); - exit(1); + struct tt_line *line = tt_add_line(tt, NULL); + if (!line) { + warn(_("failed to add line to output")); + return; } - if (g.start != 0) { - fprintf(stderr, "last arg is not the whole disk\n"); - fprintf(stderr, "call: partx -opts device wholedisk\n"); - exit(1); + + for (i = 0; i < ncolumns; i++) { + switch (get_column_id(i)) { + case COL_PARTNO: + rc = asprintf(&str, "#%2d", partno); + break; + case COL_START: + rc = asprintf(&str, "%llu", start); + break; + case COL_LENGTH: + rc = asprintf(&str, "%llu", start + size - 1); + break; + case COL_SECTORS: + rc = asprintf(&str, "%llu", size); + break; + case COL_SIZE: + rc = asprintf(&str, "%6llu MB", + (BSECTORS * size) / 1000000); + break; + case COL_NAME: + str = (char *) name; + break; + case COL_UUID: + str = (char *) uuid; + break; + default: + break; + } + + (!rc || !str ) ? + /* something weired just happened */ + tt_line_set_data(line, i, "-") : + tt_line_set_data(line, i, str); } +} - if (ioctl(fd2, HDIO_GETGEO, &g)) { - perror("HDIO_GETGEO"); - exit(1); +static void show_part(blkid_partlist ls) +{ + int i, tt_flags = 0; + struct tt *tt; + int nparts = blkid_partlist_numof_partitions(ls); + if (!nparts) + return; + + tt = tt_new_table(tt_flags); + if (!tt) { + warn(_("failed to initialize output table")); + return; } - all.start = g.start; - if (blkdev_get_sectors(fd2, &size) != 0) { - perror("partx"); - exit(1); + for (i = 0; i < ncolumns; i++) + if (!tt_define_column(tt, get_column_name(i), get_column_whint(i), 0)) + warn(_("failed to initialize output column")); + + for (i = 0; i < nparts; i++) { + blkid_partition par = blkid_partlist_get_partition(ls, i); + unsigned long long start = blkid_partition_get_start(par); + unsigned long long size = blkid_partition_get_size(par); + int partno = blkid_partition_get_partno(par); + const char *name = blkid_partition_get_name(par); + const char *uuid = blkid_partition_get_uuid(par); + + /* skip unwanted partition numbers, if any */ + if (lower && upper) + if (partno < lower || partno > upper) + continue; + if (partnumber != -1) + if (partnumber != partno) + continue; + add_line(tt, partno, start, size, name, uuid); } - all.size = (unsigned int) size; - if (verbose) - printf("device %s: start %d size %d\n", - device, all.start, all.size); + tt_print_table(tt); + tt_free_table(tt); +} - if (all.size == 0) { - fprintf(stderr, "That disk slice has size 0\n"); - exit(0); +/* old style output, backwards compatibility */ +static void show_oldpart(blkid_partlist ls, const char *device) +{ + int i, nparts = blkid_partlist_numof_partitions(ls); + if (!nparts) + return; + + for (i = 0; i < nparts; i++) { + blkid_partition par = blkid_partlist_get_partition(ls, i); + unsigned long long start = blkid_partition_get_start(par); + unsigned long long size = blkid_partition_get_size(par); + int partno = blkid_partition_get_partno(par); + + /* skip unwanted partition numbers, if any */ + if (lower && upper) + if (partno < lower || partno > upper) + continue; + if (partnumber != -1) + if (partnumber != partno) + continue; + + printf("#%2d: %9llu-%9llu (%9llu sectors, %6llu MB)\n", + partno, start, start + size -1, + size, (BSECTORS * size) / 1000000); } - 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); - } - } - } +} + +/* used for verbose option only */ +static void show_device_vinfo(blkid_probe pr, blkid_partlist ls, const char *device) +{ + unsigned long long start, size; + + if (partnumber != -1) {/* using a specific partition */ + int i, nparts = blkid_partlist_numof_partitions(ls); + for (i = 0; i < nparts; i++) { + blkid_partition par = blkid_partlist_get_partition(ls, i); + int partno = blkid_partition_get_partno(par); + + if (partnumber != partno) + continue; + + start = blkid_partition_get_start(par); + size = blkid_partition_get_size(par); + } + } + else { /* using the wholedisk */ + start = 0LL; /* this always seems to be the case! */ + size = blkid_probe_get_sectors(pr); } + printf("device %s: start %llu size %llu\n", device, start, size); +} - return 0; +static int noret usage(FILE *out) +{ + fprintf(out, _("Usage:\n" + "partx [-a|-d|-l] [--nr N-M] [partition] [wholedisk]\n" + "\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 (units of 512-byte sectors)\n" + " -s, --show-details list partitions (new format)\n\n" + + " -t, --type <TYPE> specify the partition type (dos, bsd, solaris, etc.)\n" + " -n, --nr <N-M> specify the range of partitions (--nr 2-4)\n" + " -o, --output <LIST> output column\n" + " -h, --help print this help\n\n")); + + fprintf(out, _("\nFor more information see partx(8).\n")); + exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); } -static void * -xmalloc (size_t size) { - void *t; +int main(int argc, char **argv) +{ + int fd, c; + int show, del, add; + char *type = NULL; + char *p; + char *device = NULL; /* ie: /dev/sda1 */ + char *wholedisk = NULL; /* ie: /dev/sda */ + dev_t disk; + blkid_probe pr; + blkid_partlist ls; + struct stat sb; + static const struct option long_opts[] = { + { "list", no_argument, NULL, 'l' }, + { "show-details", 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 } + }; + + /* initialize default values */ + outfmt = OLDFMT; + show = del = add = 0; + lower = upper = 0; + columns[ncolumns++] = COL_PARTNO; + columns[ncolumns++] = COL_START; + columns[ncolumns++] = COL_LENGTH; + columns[ncolumns++] = COL_SECTORS; + columns[ncolumns++] = COL_SIZE; + columns[ncolumns++] = COL_NAME; + columns[ncolumns++] = COL_UUID; + + while ((c = getopt_long(argc, argv, "lsadvn:t:o:h", long_opts, NULL)) != -1) { + switch(c) { + case 'o': + if (set_columns(optarg)) + err(EXIT_FAILURE, "set_columns failure"); + case 's': + outfmt = NEWFMT; + break; + case 'l': + show = 1; + break; + case 'a': + add = 1; + break; + case 'd': + del = 1; + break; + case 'n': + p = optarg; + lower = atoi(p); + p = strchr(p, '-'); + if (p) + upper = atoi(p+1); + else + upper = lower; + if (lower > upper) + errx(EXIT_FAILURE, _("invalid --nr option")); + break; + case 't': + type = optarg; + break; + case 'v': + verbose = 1; + break; + case 'h': + usage(stdout); + case '?': + default: + usage(stderr); + } + } - if (size == 0) - return NULL; - t = malloc (size); - if (t == NULL) { - fprintf(stderr, "Out of memory\n"); - exit(1); + /* + * Start parsing the /dev/sdaX /dev/sda options. + * 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 args (ie: /dev/sda1 /dev/sda) */ + if (upper || lower) /* cant do --nr N-M /dev/sda1 /dev/sda */ + errx_mutually_exclusive("--nr, partition"); + device = argv[optind]; + wholedisk = argv[optind+1]; } - return t; -} + else if (optind == argc-1) { + /* passed only one arg (ie: /dev/sda3 or /dev/sda) */ + device = argv[optind]; + if (stat(device, &sb) == -1) + err(EXIT_FAILURE, _("error: `%s' is not a device"), device); -static int -sseek(int fd, unsigned int secnr) { - long long in, out; - in = ((long long) secnr << 9); - out = 1; + blkid_devno_to_wholedisk(sb.st_rdev, wholedisk, sizeof(wholedisk), &disk); + wholedisk = blkid_devno_to_devname(disk); + if (!wholedisk) /* should always have a value for blkid */ + wholedisk = device; + } + else + usage(stderr); - if ((out = lseek(fd, in, SEEK_SET)) != in) - { - fprintf(stderr, "lseek error\n"); - return -1; + /* always compute this, if it's -1 we will just ignore it */ + partnumber = get_partno_from_device(device); + + if ((fd = open(wholedisk, O_RDONLY)) == -1) + err(EXIT_FAILURE, "failed to open %s", wholedisk); + + /* init libblkid (always use wholedisk, not partitions, if any) */ + pr = blkid_new_probe_from_filename(wholedisk); + if (!pr) { + close(fd); + err(EXIT_FAILURE, "%s: unable to probe device", wholedisk); + } + if (type) { + /* setup to use only the specified pt type */ + char *name[] = {type, NULL}; + blkid_probe_filter_partitions_type(pr, BLKID_FLTR_ONLYIN, name); + blkid_do_safeprobe(pr); + } + ls = blkid_probe_get_partitions(pr); + if (!ls) { + close(fd); + blkid_free_probe(pr); + /* error may depend largely on the pt type passed */ + type ? errx(EXIT_FAILURE, "%s: failed to read '%s' partition(s)", wholedisk, type): + errx(EXIT_FAILURE, "%s: failed to read partition(s)", wholedisk); } - 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)) - 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; + if (show || !(add || del)) { + if (verbose) + show_device_vinfo(pr, ls, device); + outfmt == NEWFMT ? show_part(ls) : show_oldpart(ls, device); } - return bp->block; -} -/* 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 (add) + add_part(fd, ls); - if (err != preverr) { - if (preverr) { - if (firstm == prevm) - fprintf(stderr, msg1, firstm); - else - fprintf(stderr, msg2, firstm, prevm); - errno = preverr; - perror("BLKPG"); - } - preverr = err; - firstm = prevm = m; - } else - prevm = m; + if (del) + del_part(fd, ls); + + close(fd); + blkid_free_probe(pr); + return EXIT_SUCCESS; } diff --git a/partx/partx.h b/partx/partx.h deleted file mode 100644 index 8702f25..0000000 --- a/partx/partx.h +++ /dev/null @@ -1,32 +0,0 @@ -#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); - -static inline int -four2int(unsigned char *p) { - return p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24); -} - -#endif /* PARTX_H_INCLUDED */ diff --git a/partx/solaris.c b/partx/solaris.c deleted file mode 100644 index 24075ae..0000000 --- a/partx/solaris.c +++ /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 index 30cbd9f..0000000 --- a/partx/sun.c +++ /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 (utils-linux-ng) - * Davidlohr Bueso <dave@xxxxxxx> - */ - -#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 index c131475..0000000 --- a/partx/unixware.c +++ /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; -} -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html