}
extern void strmode(mode_t mode, char *str);
+extern char *size_to_human_string(uint64_t bytes);
#endif
* Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
*/
+#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <ctype.h>
#include <errno.h>
#include <err.h>
#include <sys/stat.h>
+#include <locale.h>
+#include <string.h>
static int do_scale_by_power (uintmax_t *x, int base, int power)
{
: (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);
+}
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)
{
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
+
+++ /dev/null
-#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;
-}
+++ /dev/null
-/*
- * 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();
-}
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-#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;
-}
+++ /dev/null
-#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 */
+++ /dev/null
-/*
- efi.[ch] - Manipulates EFI variables as exported in /proc/efi/vars
-
- Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef EFI_H
-#define EFI_H
-
-/*
- * Extensible Firmware Interface
- * Based on 'Extensible Firmware Interface Specification'
- * version 1.02, 12 December, 2000
- */
-#include <stdint.h>
-
-typedef struct {
- uint8_t b[16];
-} efi_guid_t;
-
-#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \
-((efi_guid_t) \
-{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
- (b) & 0xff, ((b) >> 8) & 0xff, \
- (c) & 0xff, ((c) >> 8) & 0xff, \
- (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
-
-
-/******************************************************
- * GUIDs
- ******************************************************/
-#define NULL_GUID \
-EFI_GUID( 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
-
-static inline int
-efi_guidcmp(efi_guid_t left, efi_guid_t right)
-{
- return memcmp(&left, &right, sizeof (efi_guid_t));
-}
-
-typedef uint16_t efi_char16_t; /* UNICODE character */
-
-#endif /* EFI_H */
+++ /dev/null
-/*
- gpt.[ch]
-
- Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@dell.com>
-
- EFI GUID Partition Table handling
- Per Intel EFI Specification v1.02
- http://developer.intel.com/technology/efi/efi.htm
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include "blkdev.h"
-#include "crc32.h"
-#include "gpt.h"
-#include "partx.h"
-#include "bitops.h"
-
-static inline uint32_t
-efi_crc32(const void *buf, unsigned long len)
-{
- return (crc32(~0L, buf, len) ^ ~0L);
-}
-
-/**
- * is_pmbr_valid(): test Protective MBR for validity
- * @mbr: pointer to a legacy mbr structure
- *
- * Description: Returns 1 if PMBR is valid, 0 otherwise.
- * Validity depends on two things:
- * 1) MSDOS signature is in the last two bytes of the MBR
- * 2) One partition of type 0xEE is found
- */
-static int
-is_pmbr_valid(legacy_mbr *mbr)
-{
- int i, found = 0, signature = 0;
- if (!mbr)
- return 0;
- signature = (le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE);
- for (i = 0; signature && i < 4; i++) {
- if (mbr->partition[i].sys_type ==
- EFI_PMBR_OSTYPE_EFI_GPT) {
- found = 1;
- break;
- }
- }
- return (signature && found);
-}
-
-static int
-get_sector_size (int fd)
-{
- int sector_size;
-
- if (blkdev_get_sector_size(fd, §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;
-}
+++ /dev/null
-/*
- gpt.[ch]
-
- Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@dell.com>
-
- EFI GUID Partition Table handling
- Per Intel EFI Specification v1.02
- http://developer.intel.com/technology/efi/efi.htm
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef _GPT_H
-#define _GPT_H
-
-
-#include <inttypes.h>
-#include "partx.h"
-#include "dos.h"
-#include "efi.h"
-
-#define EFI_PMBR_OSTYPE_EFI 0xEF
-#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
-#define MSDOS_MBR_SIGNATURE 0xaa55
-#define GPT_BLOCK_SIZE 512
-
-#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
-#define GPT_HEADER_REVISION_V1_02 0x00010200
-#define GPT_HEADER_REVISION_V1_00 0x00010000
-#define GPT_HEADER_REVISION_V0_99 0x00009900
-#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
-
-typedef struct _gpt_header {
- uint64_t signature;
- uint32_t revision;
- uint32_t header_size;
- uint32_t header_crc32;
- uint32_t reserved1;
- uint64_t my_lba;
- uint64_t alternate_lba;
- uint64_t first_usable_lba;
- uint64_t last_usable_lba;
- efi_guid_t disk_guid;
- uint64_t partition_entry_lba;
- uint32_t num_partition_entries;
- uint32_t sizeof_partition_entry;
- uint32_t partition_entry_array_crc32;
- uint8_t reserved2[GPT_BLOCK_SIZE - 92];
-} __attribute__ ((packed)) gpt_header;
-
-typedef struct _gpt_entry_attributes {
- uint64_t required_to_function:1;
- uint64_t reserved:47;
- uint64_t type_guid_specific:16;
-} __attribute__ ((packed)) gpt_entry_attributes;
-
-typedef struct _gpt_entry {
- efi_guid_t partition_type_guid;
- efi_guid_t unique_partition_guid;
- uint64_t starting_lba;
- uint64_t ending_lba;
- gpt_entry_attributes attributes;
- efi_char16_t partition_name[72 / sizeof(efi_char16_t)];
-} __attribute__ ((packed)) gpt_entry;
-
-
-/*
- These values are only defaults. The actual on-disk structures
- may define different sizes, so use those unless creating a new GPT disk!
-*/
-
-#define GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE 16384
-/*
- Number of actual partition entries should be calculated
- as:
-*/
-#define GPT_DEFAULT_RESERVED_PARTITION_ENTRIES \
- (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE / \
- sizeof(gpt_entry))
-
-
-/* Protected Master Boot Record & Legacy MBR share same structure */
-/* Needs to be packed because the u16s force misalignment. */
-
-typedef struct _legacy_mbr {
- uint8_t bootcode[440];
- uint32_t unique_mbr_signature;
- uint16_t unknown;
- struct partition partition[4];
- uint16_t signature;
-} __attribute__ ((packed)) legacy_mbr;
-
-
-#define EFI_GPT_PRIMARY_PARTITION_TABLE_LBA 1
-
-/* Functions */
-int read_gpt_pt (int fd, struct slice all, struct slice *sp, int ns);
-
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
+++ /dev/null
-/*
- * Lifted from kpartx's mac.c
- *
- * Integrated to partx
- * Davidlohr Bueso <dave@gnu.org>
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-
-#include "bitops.h"
-#include "partx.h"
-
-#define MAC_PARTITION_MAGIC 0x504d
-#define MAC_DRIVER_MAGIC 0x4552
-
-struct mac_partition {
- uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */
- uint16_t res1;
- uint32_t map_count; /* # blocks in partition map */
- uint32_t start_block; /* absolute starting block # of partition */
- uint32_t block_count; /* number of blocks in partition */
- /* there is more stuff after this that we don't need */
-};
-
-/* Driver descriptor structure, in block 0 */
-struct mac_driver_desc {
- uint16_t signature; /* expected to be MAC_DRIVER_MAGIC */
- uint16_t block_size;
- uint32_t block_count;
-};
-
-int
-read_mac_pt(int fd, struct slice all, struct slice *sp, int ns) {
- struct mac_driver_desc *md;
- struct mac_partition *part;
- unsigned secsize;
- unsigned char *data;
- int blk, blocks_in_map;
- int n = 0;
-
- md = (struct mac_driver_desc *) getblock(fd, 0);
- if (md == NULL)
- return -1;
-
- if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC)
- return -1;
-
- secsize = be16_to_cpu(md->block_size);
- data = getblock(fd, secsize/512);
- if (!data)
- return -1;
- part = (struct mac_partition *) (data + secsize%512);
-
- if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
- return -1;
-
- blocks_in_map = be32_to_cpu(part->map_count);
- for (blk = 1; blk <= blocks_in_map && blk <= ns; ++blk, ++n) {
- int pos = blk * secsize;
- data = getblock(fd, pos/512);
- if (!data)
- return -1;
-
- part = (struct mac_partition *) (data + pos%512);
- if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
- break;
-
- sp[n].start = be32_to_cpu(part->start_block) * (secsize/512);
- sp[n].size = be32_to_cpu(part->block_count) * (secsize/512);
- }
- return n;
-}
.\" partx.8 --
.\" Copyright 2007 Karel Zak <kzak@redhat.com>
.\" Copyright 2007 Red Hat, Inc.
+.\" Copyright 2010 Davidlohr Bueso <dave@gnu.org>
.\" May be distributed under the GNU General Public License
-.TH PARTX 8 "11 Jan 2007"
+.TH PARTX 8 "28 Oct 2010"
.SH NAME
partx \-
-telling the kernel about presence and numbering of on-disk partitions.
+tell the linux kernel about presence and numbering of on-disk partitions.
.SH SYNOPSIS
.B partx
-.RB [ \-a | \-d | \-l ]
-.RB [ \-\-type
+.RB [ \-a | \-d | \-s ]
+.RB [ \-t
.IR TYPE ]
-.RB [ \-\-nr
-.IR M-N ]
-.RI [ partition ]
+.RB [ \-n
+.IR M:N ]
+.RI [ \- ]
.I disk
+
+.B partx
+.RB [ \-a | \-d | \-s ]
+.RB [ \-t
+.IR TYPE ]
+.I partition
+.RI [ disk ]
+
.SH DESCRIPTION
-Given a block device (
-.B disk
-) and a partition table
-.B type
-, try to parse the partition table, and list the
+Given a device or disk-image, try to parse the partition table, and list the
contents. Optionally add or remove partitions.
-This is not an fdisk - adding and removing partitions
+The
+.I disk
+argument is optional when a
+.I partition
+argument is provided. It's possible to force scannig on partition (for example
+to list nested subpartitions), then the string "-" has to be used, for example:
+
+.RS
+.br
+.B partx \-\-show \- /dev/sda3
+.RE
+
+This will use sda3 as a whole-disk rather than a partition.
+
+.B This is not an fdisk
+\- adding and removing partitions
is not a change of the disk, but just telling the kernel
about presence and numbering of on-disk partitions.
.SH OPTIONS
-.TP
-.B \-a
+.IP "\fB\-a, \-\-add\fP"
add specified partitions or read disk and add all partitions
-.TP
-.B \-d
+.IP "\fB\-b, \-\-bytes\fP"
+Print the SIZE column in bytes rather than in human readable format.
+.IP "\fB\-d, \-\-delete\fP"
delete specified or all partitions
+.IP "\fB\-l, \-\-list\fP"
+list partitions. Note that the all numbers are in 512-byte sectors. This output
+format is DEPRECATED in favour of \fB\-\-show\fP. Don't use it in newly written
+scripts.
+.IP "\fB\-g, \-\-noheadings\fP"
+Do not print a header line.
+.IP "\fB\-o, \-\-output \fIlist\fP"
+Define output columns for \fB\-\-show\fP and \fB\-\-raw\fP output. If output format is
+not specified then \fB\-\-show\fP is enable by default. Use \fB\-\-help\fP to
+get list of all supported columns.
+.IP "\fB\-r, \-\-raw\fP"
+Use raw output format.
+.IP "\fB\-s, \-\-show\fP"
+list partitions. All numbers (except SIZE) are in 512-byte sectors. The output
+columns could be (re)defined by \fB\-\-output\fP option.
+.IP "\fB\-t, \-\-type \fItype\fP"
+Specify the partition table type -- dos, bsd, solaris, unixware or gpt.
+.IP "\fB\-n, \-\-nr \fIM:N\fP"
+Specify the range of partitions. For backward compatibility is also supported
+range definition in <M-N> format. The range could be specified by negative
+numbers, for example "--nr :-1" means last partition, and "--nr -2:-1" means
+last two partition. Supported range specifications:
+.RS
.TP
-.B \-l
-list partitions. Note that the all numbers are in 512-byte sectors.
+.B <M>
+Specify only one partition (e.g. --nr 3).
.TP
-.BI --type " TYPE"
-Specify the partition type -- dos, bsd, solaris, unixware or gpt.
+.B <M:>
+Specify lower limit only (e.g. --nr 2:).
.TP
-.BI --nr " M-N"
-Specify the range of partitions (e.g --nr 2-4).
+.B <:N>
+Specify upper limit only (e.g. --nr :4).
+.TP
+.B <M:N>
+or
+.B <M-N>
+Specify lower and upper limits (e.g. --nr 2:4).
+.RE
+.SH EXAMPLES
+.IP "\fBpartx \-\-show /dev/sdb3\fP"
+.IP "\fBpartx \-\-show --nr 3 /dev/sdb\fP"
+.IP "\fBpartx \-\-show /dev/sdb3 /dev/sdb\fP"
+List partition 3 of /dev/sdb.
+.IP "\fBpartx \-\-show \- /dev/sdb3\fP"
+List all subpartitions on /dev/sdb3 (the device is used as whole-disk).
+.IP "\fBpartx \-o START -g --nr 3 /dev/sdb\fP"
+Print the start sector of partition 5 on /dev/sda without header.
+.IP "\fBpartx \-o SECTORS,SIZE /dev/sda5 /dev/sda\fP"
+List the length in sectors and human readable size of partition 5 on /dev/sda.
+.IP "\fBpartx \-\-add --nr 3:5 /dev/sdd\fP"
+Add all available partitions from 3 to 5 (inclusive) on /dev/sdd.
+.IP "\fBpartx \-d --nr :-1 /dev/sdd\fP"
+Removes last partition on /dev/sdd.
.SH SEE ALSO
.BR addpart (8),
.BR parted (8),
.BR partprobe (8)
+.SH SEE ALSO
+.nf
+Davidlohr Bueso <dave@gnu.org>
+Karel Zak <kzak@redhat.com>
+.fi
+
+The original version was written by Andries E. Brouwer <aeb@cwi.nl>.
.SH AVAILABILITY
The partx command is part of the util-linux package and is available from
ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
/*
- * Given a block device and a partition table type,
- * try to parse the partition table, and list the
- * contents. Optionally add or remove partitions.
- *
+ * partx: tell the kernel about your disk's partitions
* [This is not an fdisk - adding and removing partitions
* is not a change of the disk, but just telling the kernel
* about presence and numbering of on-disk partitions.]
*
- * Call:
- * partx [-{l|a|d}] [--type TYPE] [--nr M-N] [partition] wholedisk
- * where TYPE is {dos|bsd|solaris|unixware|gpt}.
- *
- * Read wholedisk and add all partitions:
- * partx -a wholedisk
- *
- * Subdivide a partition into slices (and delete or shrink the partition):
- * [Not easy: one needs the partition number of partition -
- * that is the last 4 or 6 bits of the minor; it can also be found
- * in /proc/partitions; but there is no good direct way.]
- * partx -a partition wholedisk
- *
- * Delete all partitions from wholedisk:
- * partx -d wholedisk
- *
- * Delete partitions M-N from wholedisk:
- * partx -d --nr M-N wholedisk
- *
* aeb, 2000-03-21 -- sah is 42 now
+ *
+ * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
+ * Rewritten to use libblkid for util-linux-ng
+ * based on ideas from Karel Zak <kzak@redhat.com>
*/
#include <stdio.h>
#include <fcntl.h>
+#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
+#include <assert.h>
#include <sys/ioctl.h>
-#include <linux/hdreg.h> /* HDIO_GETGEO */
-#ifdef HAVE_LINUX_COMPILER_H
-#include <linux/compiler.h>
-#endif
#include <linux/blkpg.h>
+#include <dirent.h>
+
+#include <blkid.h>
#include "c.h"
+#include "pathnames.h"
+#include "nls.h"
+#include "tt.h"
#include "blkdev.h"
-
+#include "strutils.h"
+#include "xalloc.h"
#include "partx.h"
-#include "crc32.h"
-static void errmerge(int err, int m, char *msg1, char *msg2);
-#define MAXTYPES 64
-#define MAXSLICES 256
+/* this is the default upper limit, could be modified by --nr */
+#define SLICES_MAX 256
+
+/* all the columns (-o option) */
+enum {
+ COL_PARTNO,
+ COL_START,
+ COL_END,
+ COL_SECTORS,
+ COL_SIZE,
+ COL_NAME,
+ COL_UUID,
+ COL_TYPE,
+ __NCOLUMNS
+};
-struct slice slices[MAXSLICES];
+enum {
+ ACT_LIST = 1,
+ ACT_SHOW,
+ ACT_ADD,
+ ACT_DELETE
+};
+
+enum {
+ FL_BYTES = (1 << 1)
+};
+
+/* column names */
+struct colinfo {
+ const char *name; /* header */
+ double whint; /* width hint (N < 1 is in percent of termwidth) */
+ int flags; /* TT_FL_* */
+ const char *help;
+};
-enum action { LIST, ADD, DELETE };
+/* columns descriptions */
+struct colinfo infos[__NCOLUMNS] = {
+ [COL_PARTNO] = { "PART", 0.25, TT_FL_RIGHT, N_("partition number") },
+ [COL_START] = { "START", 0.30, TT_FL_RIGHT, N_("start of the partition in sectors") },
+ [COL_END] = { "END", 0.30, TT_FL_RIGHT, N_("end of the partition in sectors") },
+ [COL_SECTORS] = { "SECTORS", 0.30, TT_FL_RIGHT, N_("number of sectors") },
+ [COL_SIZE] = { "SIZE", 0.30, TT_FL_RIGHT, N_("human readable size") },
+ [COL_NAME] = { "NAME", 0.30, TT_FL_TRUNC, N_("partition name") },
+ [COL_UUID] = { "UUID", 36, 0, N_("partition UUID")},
+ [COL_TYPE] = { "TYPE", 1, TT_FL_RIGHT, N_("partition type; Extended, Primary or Logical")},
+};
+/* array with IDs of enabled columns */
+static int columns[__NCOLUMNS], ncolumns;
+
+static int verbose;
+static int partx_flags;
-struct pt {
- char *type;
- ptreader *fn;
-} pts[MAXTYPES];
-int ptct;
-static void
-addpts(char *t, ptreader f)
+static inline int get_column_id(int num)
{
- if (ptct >= MAXTYPES) {
- fprintf(stderr, "addpts: too many types\n");
- exit(1);
- }
- pts[ptct].type = t;
- pts[ptct].fn = f;
- ptct++;
+ assert(ARRAY_SIZE(columns) == __NCOLUMNS);
+ assert(num < ncolumns);
+ assert(columns[num] < __NCOLUMNS);
+ return columns[num];
}
-static void
-initpts(void)
+static inline struct colinfo *get_column_info(int num)
{
- addpts("gpt", read_gpt_pt);
- addpts("dos", read_dos_pt);
- addpts("bsd", read_bsd_pt);
- addpts("solaris", read_solaris_pt);
- addpts("unixware", read_unixware_pt);
- addpts("sun", read_sun_pt);
- addpts("mac", read_mac_pt);
+ return &infos[ get_column_id(num) ];
}
-static char short_opts[] = "ladgvn:t:";
-static const struct option long_opts[] = {
- { "gpt", no_argument, NULL, 'g' },
- { "type", required_argument, NULL, 't' },
- { "nr", required_argument, NULL, 'n' },
- { NULL, 0, NULL, 0 }
-};
+static int column_name_to_id(const char *name, size_t namesz)
+{
+ int i;
-/* Used in gpt.c */
-int force_gpt=0;
-
-int
-main(int argc, char **argv){
- int fd, fd2, c, i, j, k, n;
- unsigned long long size;
- struct hd_geometry g;
- struct slice all;
- struct blkpg_ioctl_arg a;
- struct blkpg_partition pt;
- struct pt *ptp;
- enum action what = LIST;
- char *p, *type, *diskdevice, *device;
- int lower, upper;
- int verbose = 0;
- int ret = 0;
-
- initpts();
- init_crc32();
-
- lower = upper = 0;
- type = device = diskdevice = NULL;
-
- while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL))
- != -1) switch(c) {
- case 'l':
- what = LIST; break;
- case 'a':
- what = ADD; break;
- case 'd':
- what = DELETE; break;
- case 'g':
- force_gpt = 1; break;
- case 'n':
- p = optarg;
- lower = atoi(p);
- p = strchr(p, '-');
- if (p)
- upper = atoi(p+1);
- else
- upper = lower;
- break;
- case 't':
- type = optarg;
- break;
- case 'v':
- verbose = 1;
- break;
- case '?':
- default:
- fprintf(stderr, "unknown option\n");
- exit(1);
- }
+ assert(name);
- if (optind == argc-2) {
- device = argv[optind];
- diskdevice = argv[optind+1];
- } else if (optind == argc-1) {
- diskdevice = device = argv[optind];
- } else {
- fprintf(stderr, "call: partx -opts [device] wholedisk\n");
- exit(1);
- }
+ for (i = 0; i < __NCOLUMNS; i++) {
+ const char *cn = infos[i].name;
- fd = open(diskdevice, O_RDONLY);
- if (fd == -1) {
- perror(diskdevice);
- exit(1);
+ if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
+ return i;
}
+ warnx(_("unknown column: %s"), name);
+ return -1;
+}
- /* remove the indicated partitions from the kernel partition tables */
- if (what == DELETE) {
- if (device != diskdevice) {
- fprintf(stderr,
- "call: partx -d [--nr M-N] wholedisk\n");
- exit(1);
+/*
+ * Given a partition return the corresponding partition number.
+ *
+ * Note that this function tries to use sysfs, otherwise it assumes that the
+ * last characters are always numeric (sda1, sdc20, etc).
+ *
+ * Returns -1 on error.
+ */
+static int get_partno_from_device(char *partition, dev_t devno)
+{
+ int partno = 0;
+ size_t sz;
+ char *p, *end = NULL;
+
+ assert(partition);
+
+ if (devno) {
+ /* the device exits, read the partition number from /sys
+ * TODO: move this to stuff to lib/sysfs.c */
+ char path[PATH_MAX];
+ FILE *f;
+
+ snprintf(path, sizeof(path),
+ _PATH_SYS_DEVBLOCK "/%d:%d/partition",
+ major(devno), minor(devno));
+ f = fopen(path, "r");
+ if (f) {
+ if (fscanf(f, "%d", &partno) != 1)
+ partno = 0;
+ fclose(f);
}
+ if (partno)
+ return partno;
+ }
- if (!lower)
- lower = 1;
+ sz = strlen(partition);
+ p = partition + sz - 1;
- while (upper == 0 || lower <= upper) {
- int err;
+ if (!isdigit((unsigned int) *p))
+ goto err;
- if (lower > MAXSLICES)
- break;
- pt.pno = lower;
- pt.start = 0;
- pt.length = 0;
- pt.devname[0] = 0;
- pt.volname[0] = 0;
- a.op = BLKPG_DEL_PARTITION;
- a.flags = 0;
- a.datalen = sizeof(pt);
- a.data = &pt;
- if (ioctl(fd, BLKPG, &a) == -1)
- err = errno;
- else
- err = 0;
- errmerge(err, lower,
- "error deleting partition %d: ",
- "error deleting partitions %d-%d: ");
- /* expected errors:
- EBUSY: mounted or in use as swap
- ENXIO: no such nonempty partition
- EINVAL: not wholedisk, or bad pno
- EACCES/EPERM: permission denied
- */
- if (err && err != EBUSY && err != ENXIO) {
- ret = 1;
- break;
+ while (isdigit((unsigned int) *(p - 1))) p--;
+
+ errno = 0;
+ partno = strtol(p, &end, 10);
+ if (errno || !end || *end || p == end)
+ goto err;
+
+ return partno;
+err:
+ errx(EXIT_FAILURE, _("%s: failed to get partition number"), partition);
+}
+
+static int get_max_partno(const char *disk, dev_t devno)
+{
+ char path[PATH_MAX], *parent;
+ struct stat st;
+ DIR *dir;
+ struct dirent *d;
+ int partno = 0;
+
+ if (!devno && !stat(disk, &st))
+ devno = st.st_rdev;
+ if (!devno)
+ goto dflt;
+ parent = strrchr(disk, '/');
+ if (!parent)
+ goto dflt;
+ parent++;
+
+ snprintf(path, sizeof(path), _PATH_SYS_DEVBLOCK "/%d:%d/",
+ major(devno), minor(devno));
+
+ dir = opendir(path);
+ if (!dir)
+ goto dflt;
+
+ while ((d = readdir(dir))) {
+ int fd;
+
+ if (!strcmp(d->d_name, ".") ||
+ !strcmp(d->d_name, ".."))
+ continue;
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (d->d_type != DT_DIR)
+ continue;
+#endif
+ if (strncmp(parent, d->d_name, strlen(parent)))
+ continue;
+ snprintf(path, sizeof(path), "%s/partition", d->d_name);
+
+ fd = openat(dirfd(dir), path, O_RDONLY);
+ if (fd) {
+ int x = 0;
+ FILE *f = fdopen(fd, "r");
+ if (f) {
+ if (fscanf(f, "%d", &x) == 1 && x > partno)
+ partno = x;
+ fclose(f);
}
- if (err == 0 && verbose)
- printf("deleted partition %d\n", lower);
- lower++;
}
- errmerge(0, 0,
- "error deleting partition %d: ",
- "error deleting partitions %d-%d: ");
- return ret;
}
- if (device != diskdevice) {
- fd2 = open(device, O_RDONLY);
- if (fd2 == -1) {
- perror(device);
- exit(1);
+ closedir(dir);
+ return partno;
+dflt:
+ return SLICES_MAX;
+}
+
+static void del_parts_warnx(const char *device, int first, int last)
+{
+ if (first == last)
+ warnx(_("%s: error deleting partition %d"), device, first);
+ else
+ warnx(_("%s: error deleting partitions %d-%d"),
+ device, first, last);
+}
+
+static int del_parts(int fd, const char *device, dev_t devno,
+ int lower, int upper)
+{
+ int rc = 0, i, errfirst = 0, errlast = 0;
+
+ assert(fd >= 0);
+ assert(device);
+
+ if (!lower)
+ lower = 1;
+ if (!upper || lower < 0 || upper < 0) {
+ int n = get_max_partno(device, devno);
+ if (!upper)
+ upper = n;
+ else if (upper < 0)
+ upper = n + upper + 1;
+ if (lower < 0)
+ lower = n + lower + 1;
+ }
+ if (lower > upper) {
+ warnx(_("defined range <%d:%d> "
+ "does not make sense"), lower, upper);
+ return -1;
+ }
+
+ for (i = lower; i <= upper; i++) {
+ if (partx_del_partition(fd, i) == 0) {
+ if (verbose)
+ printf(_("%s: partition #%d removed\n"), device, i);
+ continue;
+ }
+ rc = -1;
+ if (verbose)
+ warn(_("%s: delete partition #%d failed"), device, i);
+ if (!errfirst)
+ errlast = errfirst = i;
+ else if (errlast + 1 == i)
+ errlast++;
+ else {
+ del_parts_warnx(device, errfirst, errlast);
+ errlast = errfirst = i;
}
- } else {
- fd2 = fd;
}
- if (ioctl(fd, HDIO_GETGEO, &g)) {
- perror("HDIO_GETGEO");
- exit(1);
+ if (errfirst)
+ del_parts_warnx(device, errfirst, errlast);
+ return rc;
+}
+
+static void add_parts_warnx(const char *device, int first, int last)
+{
+ if (first == last)
+ warnx(_("%s: error adding partition %d"), device, first);
+ else
+ warnx(_("%s: error adding partitions %d-%d"),
+ device, first, last);
+}
+
+static int add_parts(int fd, const char *device,
+ blkid_partlist ls, int lower, int upper)
+{
+ int i, nparts, rc = 0, errfirst = 0, errlast = 0;
+
+ assert(fd >= 0);
+ assert(device);
+ assert(ls);
+
+ nparts = blkid_partlist_numof_partitions(ls);
+
+ for (i = 0; i < nparts; i++) {
+ blkid_partition par = blkid_partlist_get_partition(ls, i);
+ int n = blkid_partition_get_partno(par);
+ uintmax_t start, size;
+
+ if (lower && n < lower)
+ continue;
+ if (upper && n > upper)
+ continue;
+
+ start = blkid_partition_get_start(par);
+ size = blkid_partition_get_size(par);
+
+ if (blkid_partition_is_extended(par))
+ /*
+ * Let's follow Linux kernel and reduce
+ * DOS extended partition to 1 or 2 sectors
+ */
+ size = min(size, (uintmax_t) 2);
+
+ if (partx_add_partition(fd, n, start, size) == 0) {
+ if (verbose)
+ printf(_("%s: partition #%d added\n"), device, n);
+ continue;
+ }
+ rc = -1;
+ if (verbose)
+ warn(_("%s: add partition #%d failed"), device, n);
+ if (!errfirst)
+ errlast = errfirst = n;
+ else if (errlast + 1 == n)
+ errlast++;
+ else {
+ add_parts_warnx(device, errfirst, errlast);
+ errlast = errfirst = n;
+ }
}
- if (g.start != 0) {
- fprintf(stderr, "last arg is not the whole disk\n");
- fprintf(stderr, "call: partx -opts device wholedisk\n");
- exit(1);
+
+ if (errfirst)
+ add_parts_warnx(device, errfirst, errlast);
+ return rc;
+}
+
+static int list_parts(blkid_partlist ls, int lower, int upper)
+{
+ int i, nparts;
+
+ assert(ls);
+
+ nparts = blkid_partlist_numof_partitions(ls);
+
+ for (i = 0; i < nparts; i++) {
+ blkid_partition par = blkid_partlist_get_partition(ls, i);
+ int n = blkid_partition_get_partno(par);
+ uintmax_t start, size;
+
+ if (lower && n < lower)
+ continue;
+ if (upper && n > upper)
+ continue;
+
+ start = blkid_partition_get_start(par);
+ size = blkid_partition_get_size(par);
+
+ printf("#%2d: %9ju-%9ju (%9ju sectors, %6ju MB)\n",
+ n, start, start + size -1,
+ size, (size << 9) / 1000000);
}
+ return 0;
+}
+
+static void add_tt_line(struct tt *tt, blkid_partition par)
+{
+ struct tt_line *line;
+ int i;
+
+ assert(tt);
+ assert(par);
- if (ioctl(fd2, HDIO_GETGEO, &g)) {
- perror("HDIO_GETGEO");
- exit(1);
+ line = tt_add_line(tt, NULL);
+ if (!line) {
+ warn(_("failed to add line to output"));
+ return;
}
- all.start = g.start;
- if (blkdev_get_sectors(fd2, &size) != 0) {
- perror("partx");
- exit(1);
+ for (i = 0; i < ncolumns; i++) {
+ char *str = NULL;
+ int rc = 0;
+
+ switch (get_column_id(i)) {
+ case COL_PARTNO:
+ rc = asprintf(&str, "%d",
+ blkid_partition_get_partno(par));
+ break;
+ case COL_START:
+ rc = asprintf(&str, "%ju",
+ blkid_partition_get_start(par));
+ break;
+ case COL_END:
+ rc = asprintf(&str, "%ju",
+ blkid_partition_get_start(par) +
+ blkid_partition_get_size(par) - 1);
+ break;
+ case COL_SECTORS:
+ rc = asprintf(&str, "%ju",
+ blkid_partition_get_size(par));
+ break;
+ case COL_SIZE:
+ if (partx_flags & FL_BYTES)
+ rc = asprintf(&str, "%ju", (uintmax_t)
+ blkid_partition_get_size(par) << 9);
+ else {
+ str = size_to_human_string(
+ blkid_partition_get_size(par) << 9);
+ if (str)
+ rc = 1;
+ }
+ break;
+ case COL_NAME:
+ str = (char *) blkid_partition_get_name(par);
+ break;
+ case COL_UUID:
+ str = (char *) blkid_partition_get_uuid(par);
+ break;
+ case COL_TYPE:
+ if (blkid_partition_is_primary(par))
+ str = xstrdup("P"), rc = 1;
+ else if (blkid_partition_is_logical(par))
+ str = xstrdup("L"), rc = 1;
+ else if (blkid_partition_is_extended(par))
+ str = xstrdup("E"), rc = 1;
+ break;
+ default:
+ break;
+ }
+
+ if (str && rc)
+ tt_line_set_data(line, i, str);
}
- all.size = (unsigned int) size;
+}
- if (verbose)
- printf("device %s: start %d size %d\n",
- device, all.start, all.size);
+static int show_parts(blkid_partlist ls, int tt_flags, int lower, int upper)
+{
+ int i, rc = -1;
+ struct tt *tt;
+ int nparts;
- if (all.size == 0) {
- fprintf(stderr, "That disk slice has size 0\n");
- exit(0);
+ assert(ls);
+
+ nparts = blkid_partlist_numof_partitions(ls);
+ if (!nparts)
+ return 0;
+
+ tt = tt_new_table(tt_flags);
+ if (!tt) {
+ warn(_("failed to initialize output table"));
+ return -1;
}
- if (all.size == 2)
- all.size = 0; /* probably extended partition */
- /* add the indicated partitions to the kernel partition tables */
- if (!lower)
- lower = 1;
- for (i = 0; i < ptct; i++) {
- ptp = &pts[i];
- if (!type || !strcmp(type, ptp->type)) {
- n = ptp->fn(fd, all, slices, ARRAY_SIZE(slices));
- if (n >= 0 && verbose)
- printf("%s: %d slices\n", ptp->type, n);
- if (n > 0 && (verbose || what == LIST)) {
- for (j=0; j<n; j++)
- printf("#%2d: %9d-%9d (%9d sectors, %6d MB)\n",
- lower+j,
- slices[j].start,
- slices[j].start+slices[j].size-1,
- slices[j].size,
- (int)((512 * (long long) slices[j].size)
- / 1000000));
- }
- if (n > 0 && what == ADD) {
- /* test for overlap, as in the case of an
- extended partition, and reduce size */
- for (j=0; j<n; j++) {
- for (k=j+1; k<n; k++) {
- if (slices[k].start > slices[j].start &&
- slices[k].start < slices[j].start +
- slices[j].size) {
- slices[j].size = slices[k].start -
- slices[j].start;
- if (verbose)
- printf("reduced size of "
- "partition #%d to %d\n",
- lower+j,
- slices[j].size);
- }
- }
- }
- for (j=0; j<n; j++) {
- /* skip unused/empty partitions */
- if (slices[j].size == 0)
- continue;
- pt.pno = lower+j;
- pt.start = 512 * (long long) slices[j].start;
- pt.length = 512 * (long long) slices[j].size;
- pt.devname[0] = 0;
- pt.volname[0] = 0;
- a.op = BLKPG_ADD_PARTITION;
- a.flags = 0;
- a.datalen = sizeof(pt);
- a.data = &pt;
- if (ioctl(fd, BLKPG, &a) == -1) {
- perror("BLKPG");
- fprintf(stderr,
- "error adding partition %d\n",
- lower+j);
- } else if (verbose)
- printf("added partition %d\n", lower+j);
- }
- }
+ for (i = 0; i < ncolumns; i++) {
+ struct colinfo *col = get_column_info(i);
+
+ if (!tt_define_column(tt, col->name, col->whint, col->flags)) {
+ warnx(_("failed to initialize output column"));
+ goto done;
}
}
- return 0;
-}
+ for (i = 0; i < nparts; i++) {
+ blkid_partition par = blkid_partlist_get_partition(ls, i);
+ int n = blkid_partition_get_partno(par);
-static void *
-xmalloc (size_t size) {
- void *t;
+ if (lower && n < lower)
+ continue;
+ if (upper && n > upper)
+ continue;
- if (size == 0)
- return NULL;
- t = malloc (size);
- if (t == NULL) {
- fprintf(stderr, "Out of memory\n");
- exit(1);
+ add_tt_line(tt, par);
}
- return t;
+
+ rc = 0;
+ tt_print_table(tt);
+done:
+ tt_free_table(tt);
+ return rc;
}
-static int
-sseek(int fd, unsigned int secnr) {
- long long in, out;
- in = ((long long) secnr << 9);
- out = 1;
+static int parse_range(const char *str, int *lower, int *upper)
+{
+ char *end = NULL;
+
+ if (!str)
+ return 0;
- if ((out = lseek(fd, in, SEEK_SET)) != in)
- {
- fprintf(stderr, "lseek error\n");
- return -1;
+ *upper = *lower = 0;
+ errno = 0;
+
+ if (*str == ':') { /* <:N> */
+ str++;
+ *upper = strtol(str, &end, 10);
+ if (errno || !end || *end || end == str)
+ return -1;
+ } else {
+ *upper = *lower = strtol(str, &end, 10);
+ if (errno || !end || end == str)
+ return -1;
+
+ if (*end == ':' && !*(end + 1)) /* <M:> */
+ *upper = 0;
+ else if (*end == '-' || *end == ':') { /* <M:N> <M-N> */
+ str = end + 1;
+ end = NULL;
+ errno = 0;
+ *upper = strtol(str, &end, 10);
+
+ if (errno || !end || *end || end == str)
+ return -1;
+ }
}
return 0;
}
-static
-struct block {
- unsigned int secnr;
- unsigned char *block;
- struct block *next;
-} *blockhead;
-
-unsigned char *
-getblock(int fd, unsigned int secnr) {
- struct block *bp;
-
- for (bp = blockhead; bp; bp = bp->next)
- if (bp->secnr == secnr)
- return bp->block;
- if (sseek(fd, secnr))
+static blkid_partlist get_partlist(blkid_probe pr,
+ const char *device, char *type)
+{
+ blkid_partlist ls;
+ blkid_parttable tab;
+
+ assert(pr);
+ assert(device);
+
+ if (type) {
+ char *name[] = { type, NULL };
+
+ if (blkid_probe_filter_partitions_type(pr,
+ BLKID_FLTR_ONLYIN, name)) {
+ warnx(_("failed to initialize blkid "
+ "filter for '%s'"), type);
+ return NULL;
+ }
+ }
+
+ ls = blkid_probe_get_partitions(pr);
+ if (!ls) {
+ warnx(_("%s: failed to read partition table"), device);
+ return NULL;
+ }
+
+ tab = blkid_partlist_get_table(ls);
+ if (verbose && tab)
+ printf(_("%s: partition table '%s' detected\n"),
+ device,
+ blkid_parttable_get_type(tab));
+
+ if (!blkid_partlist_numof_partitions(ls)) {
+ warnx(_("%s: %s partition table does not contains "
+ "usable partitions"), device,
+ blkid_parttable_get_type(tab));
return NULL;
- bp = xmalloc(sizeof(struct block));
- bp->secnr = secnr;
- bp->next = blockhead;
- blockhead = bp;
- bp->block = (unsigned char *) xmalloc(1024);
- if (read(fd, bp->block, 1024) != 1024) {
- fprintf(stderr, "read error, sector %d\n", secnr);
- bp->block = NULL;
}
- return bp->block;
+ return ls;
+}
+
+static int __attribute__((__noreturn__)) usage(FILE *out)
+{
+ int i;
+
+ fprintf(out, _(
+ "\nUsage:\n"
+ " %s [-a|-d|-s] [--nr <N-M> | <device>] <wholedisk>\n"),
+ program_invocation_short_name);
+
+ fprintf(out, _(
+ "\nOptions:\n"
+ " -a, --add add specified partitions or all of them\n"
+ " -d, --delete delete specified partitions or all of them\n"
+ " -l, --list list partitions (DEPRECATED)\n"
+ " -s, --show list partitions\n\n"
+
+ " -b, --bytes print SIZE in bytes rather than in human readable format\n"
+ " -g, --noheadings don't print headings for --show\n"
+ " -r, --raw use raw format output\n"
+ " -t, --type <TYPE> specify the partition type (dos, bsd, solaris, etc.)\n"
+ " -n, --nr <M:N> specify the range of partitions (--nr 2:4)\n"
+ " -o, --output <LIST> output column\n"
+ " -h, --help print this help\n\n"));
+
+ fprintf(out, _("\nAvailable columns (for --show):\n"));
+
+ for (i = 0; i < __NCOLUMNS; i++)
+ fprintf(out, " %10s %s\n", infos[i].name, gettext(infos[i].help));
+
+ fprintf(out, _("\nFor more information see partx(8).\n"));
+
+ exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+static int __attribute__((__noreturn__))
+errx_mutually_exclusive(const char *opts)
+{
+ errx(EXIT_FAILURE, "%s %s", opts, _("options are mutually exclusive"));
}
-/* call with errno and integer m and error message */
-/* merge to interval m-n */
-static void
-errmerge(int err, int m, char *msg1, char *msg2) {
- static int preverr, firstm, prevm;
-
- if (err != preverr) {
- if (preverr) {
- if (firstm == prevm)
- fprintf(stderr, msg1, firstm);
- else
- fprintf(stderr, msg2, firstm, prevm);
- errno = preverr;
- perror("BLKPG");
+int main(int argc, char **argv)
+{
+ int fd, c, what = 0, lower = 0, upper = 0, rc = 0;
+ int tt_flags = 0;
+ char *type = NULL;
+ char *device = NULL; /* pointer to atgv[], ie: /dev/sda1 */
+ char *wholedisk = NULL; /* allocated, ie: /dev/sda */
+ dev_t disk_devno = 0, part_devno = 0;
+
+ static const struct option long_opts[] = {
+ { "bytes", no_argument, NULL, 'b' },
+ { "noheadings", no_argument, NULL, 'g' },
+ { "raw", no_argument, NULL, 'r' },
+ { "list", no_argument, NULL, 'l' },
+ { "show", no_argument, NULL, 's' },
+ { "add", no_argument, NULL, 'a' },
+ { "delete", no_argument, NULL, 'd' },
+ { "type", required_argument, NULL, 't' },
+ { "nr", required_argument, NULL, 'n' },
+ { "output", required_argument, NULL, 'o' },
+ { "help", no_argument, NULL, 'h' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ while ((c = getopt_long(argc, argv, "abdglrsvn:t:o:h", long_opts, NULL)) != -1) {
+ switch(c) {
+ case 'a':
+ if (what)
+ errx_mutually_exclusive("--{add,delete,show,list,raw}");
+ what = ACT_ADD;
+ break;
+ case 'b':
+ partx_flags |= FL_BYTES;
+ break;
+ case 'd':
+ if (what)
+ errx_mutually_exclusive("--{add,delete,show,list,raw}");
+ what = ACT_DELETE;
+ break;
+ case 'g':
+ tt_flags |= TT_FL_NOHEADINGS;
+ break;
+ case 'l':
+ if (what)
+ errx_mutually_exclusive("--{add,delete,show,list,raw}");
+ what = ACT_LIST;
+ break;
+ case 'n':
+ if (parse_range(optarg, &lower, &upper))
+ errx(EXIT_FAILURE, _("failed to parse --nr <M-N> range"));
+ break;
+
+ case 'o':
+ if (tt_parse_columns_list(optarg, columns, &ncolumns,
+ column_name_to_id))
+ return EXIT_FAILURE;
+ break;
+ case 'r':
+ tt_flags |= TT_FL_RAW;
+ if (what)
+ errx_mutually_exclusive("--{add,delete,show,list,raw}");
+ what = ACT_SHOW;
+ break;
+
+ case 's':
+ if (what)
+ errx_mutually_exclusive("--{add,delete,show,list,raw}");
+ what = ACT_SHOW;
+ break;
+ case 't':
+ type = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'h':
+ usage(stdout);
+ case '?':
+ default:
+ usage(stderr);
+ }
+ }
+
+ /* -o <list> enables --show mode by default */
+ if (ncolumns && !what)
+ what = ACT_SHOW;
+
+ /* backwardly compatible default */
+ if (!what)
+ what = ACT_LIST;
+
+ /* --show default, could by modified by -o */
+ if (what == ACT_SHOW && !ncolumns) {
+ columns[ncolumns++] = COL_PARTNO;
+ columns[ncolumns++] = COL_START;
+ columns[ncolumns++] = COL_END;
+ columns[ncolumns++] = COL_SECTORS;
+ columns[ncolumns++] = COL_SIZE;
+ columns[ncolumns++] = COL_NAME;
+ columns[ncolumns++] = COL_UUID;
+ }
+
+ /*
+ * Note that 'partx /dev/sda1' == 'partx /dev/sda1 /dev/sda'
+ * so assume that the device and/or disk are always the last
+ * arguments to be passed to partx.
+ */
+ if (optind == argc - 2) {
+ /* passed 2 arguments:
+ * /dev/sda1 /dev/sda : partition + whole-disk
+ * -- /dev/sda1 : partition that should be used as a whole-disk
+ */
+ device = argv[optind];
+
+ if (strcmp(device, "-") == 0) {
+ device = NULL;
+ wholedisk = xstrdup(argv[optind + 1]);
+ } else {
+ device = argv[optind];
+ wholedisk = xstrdup(argv[optind + 1]);
+ }
+ } else if (optind == argc - 1) {
+ /* passed only one arg (ie: /dev/sda3 or /dev/sda) */
+ struct stat sb;
+
+ device = argv[optind];
+
+ if (stat(device, &sb))
+ err(EXIT_FAILURE, _("%s: stat failed"), device);
+
+ part_devno = sb.st_rdev;
+
+ if (blkid_devno_to_wholedisk(part_devno,
+ NULL, 0, &disk_devno) == 0 &&
+ part_devno != disk_devno)
+ wholedisk = blkid_devno_to_devname(disk_devno);
+
+ if (!wholedisk) {
+ wholedisk = xstrdup(device);
+ disk_devno = part_devno;
+ device = NULL;
+ part_devno = 0;
}
- preverr = err;
- firstm = prevm = m;
} else
- prevm = m;
+ usage(stderr);
+
+ if (device && (upper || lower))
+ errx(EXIT_FAILURE, _("--nr and <partition> are mutually exclusive}"));
+
+ assert(wholedisk);
+
+ if (device) {
+ /* use partno from given partition instead of --nr range, e.g:
+ * partx -d /dev/sda3
+ * is the same like:
+ * partx -d --nr 3 /dev/sda
+ */
+ struct stat sb;
+
+ if (!part_devno && !stat(device, &sb))
+ part_devno = sb.st_rdev;
+
+ lower = upper = get_partno_from_device(device, part_devno);
+ }
+
+ if (verbose)
+ printf("device: %s, whole-disk: %s, lower: %d, upper: %d\n",
+ device, wholedisk, lower, upper);
+
+ if (what == ACT_ADD || what == ACT_DELETE) {
+ struct stat x;
+
+ if (stat(wholedisk, &x) || !S_ISBLK(x.st_mode))
+ errx(EXIT_FAILURE, _("%s: not a block device"), wholedisk);
+ }
+ if ((fd = open(wholedisk, O_RDONLY)) == -1)
+ err(EXIT_FAILURE, _("%s: open failed"), wholedisk);
+
+ if (what == ACT_DELETE)
+ rc = del_parts(fd, wholedisk, disk_devno, lower, upper);
+ else {
+ blkid_probe pr = blkid_new_probe();
+ blkid_partlist ls = NULL;
+
+ if (!pr || blkid_probe_set_device(pr, fd, 0, 0))
+ warnx(_("%s: failed to initialize blkid prober"),
+ wholedisk);
+ else
+ ls = get_partlist(pr, wholedisk, type);
+
+ if (ls) {
+ int n = blkid_partlist_numof_partitions(ls);
+
+ if (lower < 0)
+ lower = n + lower + 1;
+ if (upper < 0)
+ upper = n + upper + 1;
+ if (lower > upper) {
+ warnx(_("defined range <%d:%d> "
+ "does not make sense"), lower, upper);
+ rc = -1, what = 0;
+ }
+
+ switch (what) {
+ case ACT_SHOW:
+ rc = show_parts(ls, tt_flags, lower, upper);
+ break;
+ case ACT_LIST:
+ rc = list_parts(ls, lower, upper);
+ break;
+ case ACT_ADD:
+ rc = add_parts(fd, wholedisk, ls, lower, upper);
+ break;
+ }
+ }
+ blkid_free_probe(pr);
+ }
+
+ close(fd);
+ return rc ? EXIT_FAILURE : EXIT_SUCCESS;
}
+
-#ifndef PARTX_H_INCLUDED
-#define PARTX_H_INCLUDED
-
-/*
- * For each partition type there is a routine that takes
- * a block device and a range, and returns the list of
- * slices found there in the supplied array SP that can
- * hold NS entries. The return value is the number of
- * entries stored, or -1 if the appropriate type is not
- * present.
- */
-
-
-/* units: 512 byte sectors */
-struct slice {
- unsigned int start;
- unsigned int size;
-};
-
-typedef int (ptreader)(int fd, struct slice all, struct slice *sp, int ns);
-
-extern ptreader read_dos_pt, read_bsd_pt, read_solaris_pt, read_unixware_pt, read_gpt_pt;
-extern ptreader read_sun_pt, read_mac_pt;
-
-unsigned char *getblock(int fd, unsigned int secnr);
+#ifndef UTIL_LINUX_PARTX_H
+#define UTIL_LINUX_PARTX_H
+
+#include <sys/ioctl.h>
+#include <linux/blkpg.h>
+
+static inline int partx_del_partition(int fd, int partno)
+{
+ struct blkpg_ioctl_arg a;
+ struct blkpg_partition p;
+
+ p.pno = partno;
+ p.start = 0;
+ p.length = 0;
+ p.devname[0] = 0;
+ p.volname[0] = 0;
+ a.op = BLKPG_DEL_PARTITION;
+ a.flags = 0;
+ a.datalen = sizeof(p);
+ a.data = &p;
+
+ return ioctl(fd, BLKPG, &a);
+}
-static inline int
-four2int(unsigned char *p) {
- return p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24);
+static inline int partx_add_partition(int fd, int partno,
+ unsigned long start, unsigned long size)
+{
+ struct blkpg_ioctl_arg a;
+ struct blkpg_partition p;
+
+ p.pno = partno;
+ p.start = start << 9;
+ p.length = size << 9;
+ p.devname[0] = 0;
+ p.volname[0] = 0;
+ a.op = BLKPG_ADD_PARTITION;
+ a.flags = 0;
+ a.datalen = sizeof(p);
+ a.data = &p;
+
+ return ioctl(fd, BLKPG, &a);
}
-#endif /* PARTX_H_INCLUDED */
+#endif /* UTIL_LINUX_PARTX_H */
+++ /dev/null
-#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;
-}
-
+++ /dev/null
-/*
- * Lifted from kpartx's sun.c
- *
- * Copyrights of the original file apply
- * Copyright (c) 2007 Hannes Reinecke
- *
- * Integrated to partx
- * Davidlohr Bueso <dave@gnu.org>
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-
-#include "bitops.h"
-#include "partx.h"
-
-#define SUN_DISK_MAGIC 0xDABE /* Disk magic number */
-#define SUN_DISK_MAXPARTITIONS 8
-
-struct __attribute__ ((packed)) sun_raw_part {
- u_int32_t start_cylinder; /* where the part starts... */
- u_int32_t num_sectors; /* ...and it's length */
-};
-
-struct __attribute__ ((packed)) sun_part_info {
- u_int8_t spare1;
- u_int8_t id; /* Partition type */
- u_int8_t spare2;
- u_int8_t flags; /* Partition flags */
-};
-
-struct __attribute__ ((packed)) sun_disk_label {
- char info[128]; /* Informative text string */
- u_int8_t spare0[14];
- struct sun_part_info infos[SUN_DISK_MAXPARTITIONS];
- u_int8_t spare1[246]; /* Boot information etc. */
- u_int16_t rspeed; /* Disk rotational speed */
- u_int16_t pcylcount; /* Physical cylinder count */
- u_int16_t sparecyl; /* extra sects per cylinder */
- u_int8_t spare2[4]; /* More magic... */
- u_int16_t ilfact; /* Interleave factor */
- u_int16_t ncyl; /* Data cylinder count */
- u_int16_t nacyl; /* Alt. cylinder count */
- u_int16_t ntrks; /* Tracks per cylinder */
- u_int16_t nsect; /* Sectors per track */
- u_int8_t spare3[4]; /* Even more magic... */
- struct sun_raw_part partitions[SUN_DISK_MAXPARTITIONS];
- u_int16_t magic; /* Magic number */
- u_int16_t csum; /* Label xor'd checksum */
-};
-
-/* Checksum Verification */
-static int
-sun_verify_checksum (struct sun_disk_label *label)
-{
- u_int16_t *ush = ((u_int16_t *)(label + 1)) - 1;
- u_int16_t csum = 0;
-
- while (ush >= (u_int16_t *)label)
- csum ^= *ush--;
-
- return !csum;
-}
-
-int
-read_sun_pt(int fd, struct slice all, struct slice *sp, int ns) {
- struct sun_disk_label *l;
- struct sun_raw_part *s;
- unsigned int offset = all.start, end;
- int i, j, n;
- unsigned char *bp;
-
- bp = getblock(fd, offset);
- if (bp == NULL)
- return -1;
-
- l = (struct sun_disk_label *) bp;
- if(be16_to_cpu(l->magic) != SUN_DISK_MAGIC)
- return -1;
-
- if (!sun_verify_checksum(l)) {
- fprintf(stderr, "Corrupted Sun disk label\n");
- return -1;
- }
-
- for(i=0, n=0; i<SUN_DISK_MAXPARTITIONS; i++) {
- s = &l->partitions[i];
-
- if (s->num_sectors == 0)
- continue;
- if (n < ns) {
- sp[n].start = offset +
- be32_to_cpu(s->start_cylinder) * be16_to_cpu(l->nsect) * be16_to_cpu(l->ntrks);
- sp[n].size = be32_to_cpu(s->num_sectors);
- n++;
- } else {
- fprintf(stderr,
- "sun_disklabel: too many slices\n");
- break;
- }
- }
- /*
- * Convention has it that the SUN disklabel will always have
- * the 'c' partition spanning the entire disk.
- * So we have to check for contained slices.
- */
- for(i = 0; i < SUN_DISK_MAXPARTITIONS; i++) {
- if (sp[i].size == 0)
- continue;
-
- end = sp[i].start + sp[i].size;
- for(j = 0; j < SUN_DISK_MAXPARTITIONS; j ++) {
- if ( i == j )
- continue;
- if (sp[j].size == 0)
- continue;
-
- if (sp[i].start < sp[j].start) {
- if (end > sp[j].start &&
- end < sp[j].start + sp[j].size) {
- /* Invalid slice */
- fprintf(stderr,
- "sun_disklabel: slice %d overlaps with %d\n", i , j);
- sp[i].size = 0;
- }
- }
- }
- }
- return n;
-}
+++ /dev/null
-#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;
-}