summaryrefslogtreecommitdiffstats
path: root/partx
diff options
context:
space:
mode:
Diffstat (limited to 'partx')
-rw-r--r--partx/Makefile3
-rw-r--r--partx/crc32.c393
-rw-r--r--partx/crc32.h19
-rw-r--r--partx/dos.c27
-rw-r--r--partx/dos.h13
-rw-r--r--partx/efi.h57
-rw-r--r--partx/gpt.c630
-rw-r--r--partx/gpt.h131
-rw-r--r--partx/partx.c26
-rw-r--r--partx/partx.h7
-rw-r--r--partx/unixware.c4
11 files changed, 1289 insertions, 21 deletions
diff --git a/partx/Makefile b/partx/Makefile
index 39237e019..9f9a9dbe9 100644
--- a/partx/Makefile
+++ b/partx/Makefile
@@ -1,4 +1,5 @@
-OBJ = bsd.o dos.o partx.o solaris.o unixware.o
+OBJ = bsd.o dos.o partx.o solaris.o unixware.o gpt.o crc32.o
+CFLAGS += -Wall
all: addpart delpart partx
diff --git a/partx/crc32.c b/partx/crc32.c
new file mode 100644
index 000000000..42d803d14
--- /dev/null
+++ b/partx/crc32.c
@@ -0,0 +1,393 @@
+/*
+ * 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)
+{
+ if (crc32table_le) 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)
+{
+ if (crc32table_be) 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
new file mode 100644
index 000000000..a4505b842
--- /dev/null
+++ b/partx/crc32.h
@@ -0,0 +1,19 @@
+/*
+ * crc32.h
+ */
+#ifndef _CRC32_H
+#define _CRC32_H
+
+#include <inttypes.h>
+#include <stdlib.h>
+
+extern int init_crc32(void);
+extern void cleanup_crc32(void);
+extern uint32_t crc32_le(uint32_t crc, unsigned char const *p, size_t len);
+extern uint32_t crc32_be(uint32_t crc, unsigned char const *p, size_t len);
+
+#define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)data, length)
+#define ether_crc_le(length, data) crc32_le(~0, data, length)
+#define ether_crc(length, data) crc32_be(~0, data, length)
+
+#endif /* _CRC32_H */
diff --git a/partx/dos.c b/partx/dos.c
index b32801e0b..7b61d0b05 100644
--- a/partx/dos.c
+++ b/partx/dos.c
@@ -1,14 +1,6 @@
#include <stdio.h>
#include "partx.h"
-
-struct partition {
- unsigned char boot_ind; /* 0x80 - active */
- unsigned char bh, bs, bc;
- unsigned char sys_type;
- unsigned char eh, es, ec;
- unsigned int start_sect;
- unsigned int nr_sects;
-};
+#include "dos.h"
static int
is_extended(int type) {
@@ -17,9 +9,10 @@ is_extended(int type) {
static int
read_extended_partition(int fd, struct partition *ep,
- struct slice *sp, int ns) {
+ struct slice *sp, int ns)
+{
struct partition *p;
- unsigned long start, here, next;
+ unsigned long start, here;
unsigned char *bp;
int loopct = 0;
int moretodo = 1;
@@ -68,6 +61,11 @@ read_extended_partition(int fd, struct partition *ep,
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;
@@ -84,6 +82,13 @@ read_dos_pt(int fd, struct slice all, struct slice *sp, int ns) {
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 = p->start_sect;
diff --git a/partx/dos.h b/partx/dos.h
new file mode 100644
index 000000000..429f3d391
--- /dev/null
+++ b/partx/dos.h
@@ -0,0 +1,13 @@
+#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 int start_sect;
+ unsigned int nr_sects;
+};
+
+#endif /* DOS_H_INCLUDED */
diff --git a/partx/efi.h b/partx/efi.h
new file mode 100644
index 000000000..fcf274094
--- /dev/null
+++ b/partx/efi.h
@@ -0,0 +1,57 @@
+/*
+ efi.[ch] - Manipulates EFI variables as exported in /proc/efi/vars
+
+ Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef EFI_H
+#define EFI_H
+
+/*
+ * Extensible Firmware Interface
+ * Based on 'Extensible Firmware Interface Specification'
+ * version 1.02, 12 December, 2000
+ */
+#include <stdint.h>
+
+typedef struct {
+ uint8_t b[16];
+} efi_guid_t;
+
+#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \
+((efi_guid_t) \
+{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
+ (b) & 0xff, ((b) >> 8) & 0xff, \
+ (c) & 0xff, ((c) >> 8) & 0xff, \
+ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
+
+
+/******************************************************
+ * GUIDs
+ ******************************************************/
+#define NULL_GUID \
+EFI_GUID( 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
+
+static inline int
+efi_guidcmp(efi_guid_t left, efi_guid_t right)
+{
+ return memcmp(&left, &right, sizeof (efi_guid_t));
+}
+
+typedef uint16_t efi_char16_t; /* UNICODE character */
+
+#endif /* EFI_H */
diff --git a/partx/gpt.c b/partx/gpt.c
new file mode 100644
index 000000000..bf90fdeb3
--- /dev/null
+++ b/partx/gpt.c
@@ -0,0 +1,630 @@
+/*
+ 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
+*/
+
+#define _FILE_OFFSET_BITS 64
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <asm/byteorder.h>
+#include "crc32.h"
+#include "gpt.h"
+#include "partx.h"
+
+#define BLKGETLASTSECT _IO(0x12,108) /* get last sector of block device */
+#define BLKGETSIZE _IO(0x12,96) /* return device size */
+#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
+#define BLKGETSIZE64 _IOR(0x12,114,sizeof(uint64_t)) /* return device size in bytes (u64 *arg) */
+
+struct blkdev_ioctl_param {
+ unsigned int block;
+ size_t content_length;
+ char * block_contents;
+};
+
+/**
+ * efi_crc32() - EFI version of crc32 function
+ * @buf: buffer to calculate crc32 of
+ * @len - length of buf
+ *
+ * Description: Returns EFI-style CRC32 value for @buf
+ *
+ * This function uses the little endian Ethernet polynomial
+ * but seeds the function with ~0, and xor's with ~0 at the end.
+ * Note, the EFI Specification, v1.02, has a reference to
+ * Dr. Dobbs Journal, May 1994 (actually it's in May 1992).
+ */
+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);
+}
+
+
+/************************************************************
+ * get_sector_size
+ * Requires:
+ * - filedes is an open file descriptor, suitable for reading
+ * Modifies: nothing
+ * Returns:
+ * sector size, or 512.
+ ************************************************************/
+static int
+get_sector_size(int filedes)
+{
+ int rc, sector_size = 512;
+
+ rc = ioctl(filedes, BLKSSZGET, &sector_size);
+ if (rc)
+ sector_size = 512;
+ return sector_size;
+}
+
+/************************************************************
+ * _get_num_sectors
+ * Requires:
+ * - filedes is an open file descriptor, suitable for reading
+ * Modifies: nothing
+ * Returns:
+ * Last LBA value on success
+ * 0 on error
+ *
+ * Try getting BLKGETSIZE64 and BLKSSZGET first,
+ * then BLKGETSIZE if necessary.
+ * Kernels 2.4.15-2.4.18 and 2.5.0-2.5.3 have a broken BLKGETSIZE64
+ * which returns the number of 512-byte sectors, not the size of
+ * the disk in bytes. Fixed in kernels 2.4.18-pre8 and 2.5.4-pre3.
+ ************************************************************/
+static uint64_t
+_get_num_sectors(int filedes)
+{
+ unsigned long sectors=0;
+ int rc;
+#if 0
+ uint64_t bytes=0;
+
+ rc = ioctl(filedes, BLKGETSIZE64, &bytes);
+ if (!rc)
+ return bytes / get_sector_size(filedes);
+#endif
+ rc = ioctl(filedes, BLKGETSIZE, &sectors);
+ if (rc)
+ return 0;
+
+ return sectors;
+}
+
+/************************************************************
+ * last_lba(): return number of last logical block of device
+ *
+ * @fd
+ *
+ * Description: returns Last LBA value on success, 0 on error.
+ * Notes: The value st_blocks gives the size of the file
+ * in 512-byte blocks, which is OK if
+ * EFI_BLOCK_SIZE_SHIFT == 9.
+ ************************************************************/
+
+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_lastoddsector(int fd, uint64_t lba, void *buffer, size_t count)
+{
+ int rc;
+ struct blkdev_ioctl_param ioctl_param;
+
+ if (!buffer) return 0;
+
+ ioctl_param.block = 0; /* read the last sector */
+ ioctl_param.content_length = count;
+ ioctl_param.block_contents = buffer;
+
+ rc = ioctl(fd, BLKGETLASTSECT, &ioctl_param);
+ if (rc == -1) perror("read failed");
+
+ return !rc;
+}
+
+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;
+ ssize_t bytesread;
+
+ lseek(fd, offset, SEEK_SET);
+ bytesread = read(fd, buffer, bytes);
+
+ /* Kludge. This is necessary to read/write the last
+ block of an odd-sized disk, until Linux 2.5.x kernel fixes.
+ This is only used by gpt.c, and only to read
+ one sector, so we don't have to be fancy.
+ */
+ if (!bytesread && !(last_lba(fd) & 1) && lba == last_lba(fd)) {
+ bytesread = read_lastoddsector(fd, lba, buffer, bytes);
+ }
+ return bytesread;
+}
+
+/**
+ * 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) {
+ if (gpt)
+ free (gpt);
+ if (ptes)
+ 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);
+ last_used_index=n;
+ n++;
+ }
+ }
+ free (ptes);
+ free (gpt);
+ return last_used_index+1;
+}
+
+
+/*
+ * 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/gpt.h b/partx/gpt.h
new file mode 100644
index 000000000..d0a81f5f2
--- /dev/null
+++ b/partx/gpt.h
@@ -0,0 +1,131 @@
+/*
+ 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 0x5452415020494645
+#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/partx.c b/partx/partx.c
index 212f651b6..f56c2d57e 100644
--- a/partx/partx.c
+++ b/partx/partx.c
@@ -9,7 +9,7 @@
*
* Call:
* partx [-{l|a|d}] [--type TYPE] [--nr M-N] [partition] wholedisk
- * where TYPE is {dos|bsd|solaris|unixware}.
+ * where TYPE is {dos|bsd|solaris|unixware|gpt}.
*
* Read wholedisk and add all partitions:
* partx -a wholedisk
@@ -35,12 +35,14 @@
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
+#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/blkpg.h>
#define BLKGETSIZE _IO(0x12,96) /* return device size */
#include "partx.h"
+#include "crc32.h"
static void errmerge(int err, int m, char *msg1, char *msg2);
#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
@@ -58,7 +60,9 @@ struct pt {
} pts[MAXTYPES];
int ptct;
-addpts(char *t, ptreader f) {
+static void
+addpts(char *t, ptreader f)
+{
if (ptct >= MAXTYPES) {
fprintf(stderr, "addpts: too many types\n");
exit(1);
@@ -68,20 +72,27 @@ addpts(char *t, ptreader f) {
ptct++;
}
-initpts(){
+static void
+initpts(void)
+{
+ 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);
}
-static char short_opts[] = "ladvn:t:";
+static char short_opts[] = "ladgvn:t:";
static const struct option long_opts[] = {
+ { "gpt", no_argument, NULL, 'g' },
{ "type", required_argument, NULL, 't' },
{ "nr", required_argument, NULL, 'n' },
{ NULL, 0, NULL, 0 }
};
+/* Used in gpt.c */
+int force_gpt=0;
+
int
main(int argc, char **argv){
int fd, fd2, c, i, j, k, n;
@@ -98,6 +109,7 @@ main(int argc, char **argv){
int ret = 0;
initpts();
+ init_crc32();
lower = upper = 0;
type = device = diskdevice = NULL;
@@ -110,6 +122,8 @@ main(int argc, char **argv){
what = ADD; break;
case 'd':
what = DELETE; break;
+ case 'g':
+ force_gpt=1; break;
case 'n':
p = optarg;
lower = atoi(p);
@@ -256,8 +270,8 @@ main(int argc, char **argv){
slices[j].start,
slices[j].start+slices[j].size-1,
slices[j].size,
- ((512 * (long long) slices[j].size)
- / 1000000));
+ (int)((512 * (long long) slices[j].size)
+ / 1000000));
}
if (n > 0 && what == ADD) {
/* test for overlap, as in the case of an
diff --git a/partx/partx.h b/partx/partx.h
index b96588a59..efaa0640a 100644
--- a/partx/partx.h
+++ b/partx/partx.h
@@ -1,3 +1,6 @@
+#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
@@ -16,7 +19,7 @@ struct slice {
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;
+extern ptreader read_dos_pt, read_bsd_pt, read_solaris_pt, read_unixware_pt, read_gpt_pt;
char *getblock(int fd, unsigned int secnr);
@@ -24,3 +27,5 @@ static inline int
four2int(unsigned char *p) {
return p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24);
}
+
+#endif /* PARTX_H_INCLUDED */
diff --git a/partx/unixware.c b/partx/unixware.c
index 3b3f21e16..34cc226a7 100644
--- a/partx/unixware.c
+++ b/partx/unixware.c
@@ -3,8 +3,8 @@
#define UNIXWARE_FS_UNUSED 0
#define UNIXWARE_NUMSLICE 16
-#define UNIXWARE_DISKMAGIC (0xCA5E600DUL)
-#define UNIXWARE_DISKMAGIC2 (0x600DDEEEUL)
+#define UNIXWARE_DISKMAGIC (0xCA5E600D)
+#define UNIXWARE_DISKMAGIC2 (0x600DDEEE)
struct unixware_slice {
unsigned short s_label; /* label */