diff -urNp --exclude-from=/home/mdomsch/excludes util-linux-2.11o/partx/Makefile util-linux-2.11o.gpt/partx/Makefile
--- util-linux-2.11o/partx/Makefile	Wed Mar 22 16:19:06 2000
+++ util-linux-2.11o.gpt/partx/Makefile	Mon Apr  8 16:20:34 2002
@@ -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 -urNp --exclude-from=/home/mdomsch/excludes util-linux-2.11o/partx/crc32.c util-linux-2.11o.gpt/partx/crc32.c
--- util-linux-2.11o/partx/crc32.c	Wed Dec 31 18:00:00 1969
+++ util-linux-2.11o.gpt/partx/crc32.c	Mon Apr  8 13:41:35 2002
@@ -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 -urNp --exclude-from=/home/mdomsch/excludes util-linux-2.11o/partx/crc32.h util-linux-2.11o.gpt/partx/crc32.h
--- util-linux-2.11o/partx/crc32.h	Wed Dec 31 18:00:00 1969
+++ util-linux-2.11o.gpt/partx/crc32.h	Mon Apr  8 13:41:35 2002
@@ -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 -urNp --exclude-from=/home/mdomsch/excludes util-linux-2.11o/partx/dos.c util-linux-2.11o.gpt/partx/dos.c
--- util-linux-2.11o/partx/dos.c	Tue Mar 21 17:43:00 2000
+++ util-linux-2.11o.gpt/partx/dos.c	Mon Apr  8 13:41:35 2002
@@ -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 p
 	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;
@@ -82,6 +80,13 @@ read_dos_pt(int fd, struct slice all, st
 	if (bp[510] != 0x55 || bp[511] != 0xaa)
 		return -1;
 
+	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 */
diff -urNp --exclude-from=/home/mdomsch/excludes util-linux-2.11o/partx/dos.h util-linux-2.11o.gpt/partx/dos.h
--- util-linux-2.11o/partx/dos.h	Wed Dec 31 18:00:00 1969
+++ util-linux-2.11o.gpt/partx/dos.h	Mon Apr  8 13:41:35 2002
@@ -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 -urNp --exclude-from=/home/mdomsch/excludes util-linux-2.11o/partx/efi.h util-linux-2.11o.gpt/partx/efi.h
--- util-linux-2.11o/partx/efi.h	Wed Dec 31 18:00:00 1969
+++ util-linux-2.11o.gpt/partx/efi.h	Mon Apr  8 17:13:18 2002
@@ -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 -urNp --exclude-from=/home/mdomsch/excludes util-linux-2.11o/partx/gpt.c util-linux-2.11o.gpt/partx/gpt.c
--- util-linux-2.11o/partx/gpt.c	Wed Dec 31 18:00:00 1969
+++ util-linux-2.11o.gpt/partx/gpt.c	Mon Apr  8 17:07:25 2002
@@ -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;
+        uint64_t bytes=0;
+	int rc;
+
+#if 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 -urNp --exclude-from=/home/mdomsch/excludes util-linux-2.11o/partx/gpt.h util-linux-2.11o.gpt/partx/gpt.h
--- util-linux-2.11o/partx/gpt.h	Wed Dec 31 18:00:00 1969
+++ util-linux-2.11o.gpt/partx/gpt.h	Mon Apr  8 17:12:44 2002
@@ -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 -urNp --exclude-from=/home/mdomsch/excludes util-linux-2.11o/partx/partx.c util-linux-2.11o.gpt/partx/partx.c
--- util-linux-2.11o/partx/partx.c	Wed Mar 22 16:25:34 2000
+++ util-linux-2.11o.gpt/partx/partx.c	Mon Apr  8 17:17:24 2002
@@ -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 -urNp --exclude-from=/home/mdomsch/excludes util-linux-2.11o/partx/partx.h util-linux-2.11o.gpt/partx/partx.h
--- util-linux-2.11o/partx/partx.h	Tue Mar 21 15:54:58 2000
+++ util-linux-2.11o.gpt/partx/partx.h	Mon Apr  8 17:11:56 2002
@@ -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 -urNp --exclude-from=/home/mdomsch/excludes util-linux-2.11o/partx/unixware.c util-linux-2.11o.gpt/partx/unixware.c
--- util-linux-2.11o/partx/unixware.c	Tue Mar 21 15:54:33 2000
+++ util-linux-2.11o.gpt/partx/unixware.c	Mon Apr  8 16:53:01 2002
@@ -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 */
