From c4ecaf21d59671ac7ec0bd26bd2c346c98c7771c Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Thu, 9 Dec 2010 21:54:17 +0100 Subject: [PATCH] partx: complete rewrite Co-Author: Karel Zak Signed-off-by: Davidlohr Bueso Signed-off-by: Karel Zak --- include/strutils.h | 1 + lib/strutils.c | 49 ++ misc-utils/lsblk.c | 46 -- partx/Makefile.am | 20 +- 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 | 117 ++++- partx/partx.c | 1082 +++++++++++++++++++++++++++++++------------- partx/partx.h | 70 +-- partx/solaris.c | 69 --- partx/sun.c | 130 ------ partx/unixware.c | 83 ---- 19 files changed, 955 insertions(+), 2130 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/solaris.c delete mode 100644 partx/sun.c delete mode 100644 partx/unixware.c diff --git a/include/strutils.h b/include/strutils.h index 31cf8060..462332d9 100644 --- a/include/strutils.h +++ b/include/strutils.h @@ -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 diff --git a/lib/strutils.c b/lib/strutils.c index dcae9f2d..e8e86865 100644 --- a/lib/strutils.c +++ b/lib/strutils.c @@ -3,12 +3,15 @@ * Copyright (C) 2010 Davidlohr Bueso */ +#include #include #include #include #include #include #include +#include +#include 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); +} diff --git a/misc-utils/lsblk.c b/misc-utils/lsblk.c index 6c5a205d..745a3e61 100644 --- a/misc-utils/lsblk.c +++ b/misc-utils/lsblk.c @@ -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) { diff --git a/partx/Makefile.am b/partx/Makefile.am index a26963ed..f7eeef88 100644 --- a/partx/Makefile.am +++ b/partx/Makefile.am @@ -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 index 4532c324..00000000 --- a/partx/bsd.c +++ /dev/null @@ -1,83 +0,0 @@ -#include -#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 4120f728..00000000 --- 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< 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 a4505b84..00000000 --- a/partx/crc32.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * crc32.h - */ -#ifndef _CRC32_H -#define _CRC32_H - -#include -#include - -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 f962f376..00000000 --- a/partx/dos.c +++ /dev/null @@ -1,138 +0,0 @@ -#include - -#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 877beecd..00000000 --- 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 fcf27409..00000000 --- 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 - - 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 - -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 be612fc9..00000000 --- a/partx/gpt.c +++ /dev/null @@ -1,510 +0,0 @@ -/* - gpt.[ch] - - Copyright (C) 2000-2001 Dell Computer Corporation - - 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 -#include -#include -#include -#include -#include -#include -#include - -#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 39814b5d..00000000 --- a/partx/gpt.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - gpt.[ch] - - Copyright (C) 2000-2001 Dell Computer Corporation - - 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 -#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 11de6bd9..00000000 --- a/partx/mac.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Lifted from kpartx's mac.c - * - * Integrated to partx - * Davidlohr Bueso - */ - -#include -#include -#include - -#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 b24bc87b..efd7dbd5 100644 --- a/partx/partx.8 +++ b/partx/partx.8 @@ -1,48 +1,112 @@ .\" partx.8 -- .\" Copyright 2007 Karel Zak .\" Copyright 2007 Red Hat, Inc. +.\" Copyright 2010 Davidlohr Bueso .\" 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 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 +Specify only one partition (e.g. --nr 3). .TP -.BI --type " TYPE" -Specify the partition type -- dos, bsd, solaris, unixware or gpt. +.B +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 +or +.B +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 +Karel Zak +.fi + +The original version was written by Andries E. Brouwer . .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/. diff --git a/partx/partx.c b/partx/partx.c index aa5a2ad8..e0f1f2a9 100644 --- a/partx/partx.c +++ b/partx/partx.c @@ -1,404 +1,834 @@ /* - * Given a block device and a partition table type, - * try to parse the partition table, and list the - * contents. Optionally add or remove partitions. - * + * partx: tell the kernel about your disk's partitions * [This is not an fdisk - adding and removing partitions * is not a change of the disk, but just telling the kernel * about presence and numbering of on-disk partitions.] * - * Call: - * partx [-{l|a|d}] [--type TYPE] [--nr M-N] [partition] wholedisk - * where TYPE is {dos|bsd|solaris|unixware|gpt}. - * - * Read wholedisk and add all partitions: - * partx -a wholedisk - * - * Subdivide a partition into slices (and delete or shrink the partition): - * [Not easy: one needs the partition number of partition - - * that is the last 4 or 6 bits of the minor; it can also be found - * in /proc/partitions; but there is no good direct way.] - * partx -a partition wholedisk - * - * Delete all partitions from wholedisk: - * partx -d wholedisk - * - * Delete partitions M-N from wholedisk: - * partx -d --nr M-N wholedisk - * * aeb, 2000-03-21 -- sah is 42 now + * + * Copyright (C) 2010 Davidlohr Bueso + * Rewritten to use libblkid for util-linux-ng + * based on ideas from Karel Zak */ #include #include +#include #include #include #include +#include #include +#include +#include #include +#include #include -#include /* HDIO_GETGEO */ -#ifdef HAVE_LINUX_COMPILER_H -#include -#endif #include +#include + +#include #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 0 && what == ADD) { - /* test for overlap, as in the case of an - extended partition, and reduce size */ - for (j=0; j 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; jname, 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)) /* */ + *upper = 0; + else if (*end == '-' || *end == ':') { /* */ + 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"), + 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 specify the partition type (dos, bsd, solaris, etc.)\n" + " -n, --nr specify the range of partitions (--nr 2:4)\n" + " -o, --output 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 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 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 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; } + diff --git a/partx/partx.h b/partx/partx.h index 8702f259..b40fa8fb 100644 --- a/partx/partx.h +++ b/partx/partx.h @@ -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 +#include + +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 index 24075aed..00000000 --- a/partx/solaris.c +++ /dev/null @@ -1,69 +0,0 @@ -#include -#include /* time_t */ -#include -#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; iv_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 5bfe2ad8..00000000 --- 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 - * Davidlohr Bueso - */ - -#include -#include - -#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; ipartitions[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 c131475f..00000000 --- a/partx/unixware.c +++ /dev/null @@ -1,83 +0,0 @@ -#include -#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; -} -- 2.39.5