diff -BurNp --exclude-from=/home/mdomsch/excludes util-linux-2.11n/partx/Makefile util-linux/partx/Makefile
--- util-linux-2.11n/partx/Makefile	Wed Mar 22 16:19:06 2000
+++ util-linux/partx/Makefile	Wed Jan 16 22:10:16 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 -BurNp --exclude-from=/home/mdomsch/excludes util-linux-2.11n/partx/crc32.c util-linux/partx/crc32.c
--- util-linux-2.11n/partx/crc32.c	Wed Dec 31 18:00:00 1969
+++ util-linux/partx/crc32.c	Tue Jan 15 21:53:53 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 -BurNp --exclude-from=/home/mdomsch/excludes util-linux-2.11n/partx/crc32.h util-linux/partx/crc32.h
--- util-linux-2.11n/partx/crc32.h	Wed Dec 31 18:00:00 1969
+++ util-linux/partx/crc32.h	Tue Jan 15 21:55:05 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 -BurNp --exclude-from=/home/mdomsch/excludes util-linux-2.11n/partx/dos.c util-linux/partx/dos.c
--- util-linux-2.11n/partx/dos.c	Tue Mar 21 17:43:00 2000
+++ util-linux/partx/dos.c	Wed Jan 16 17:06:21 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;
@@ -84,6 +82,13 @@ read_dos_pt(int fd, struct slice all, st
 
 	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 -BurNp --exclude-from=/home/mdomsch/excludes util-linux-2.11n/partx/dos.h util-linux/partx/dos.h
--- util-linux-2.11n/partx/dos.h	Wed Dec 31 18:00:00 1969
+++ util-linux/partx/dos.h	Wed Jan 16 22:11:57 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 -BurNp --exclude-from=/home/mdomsch/excludes util-linux-2.11n/partx/gpt.c util-linux/partx/gpt.c
--- util-linux-2.11n/partx/gpt.c	Wed Dec 31 18:00:00 1969
+++ util-linux/partx/gpt.c	Wed Jan 16 22:26:18 2002
@@ -0,0 +1,690 @@
+/************************************************************
+ * EFI GUID Partition Table handling
+ * Per Intel EFI Specification v1.02
+ * http://developer.intel.com/technology/efi/efi.htm
+ * efi.[ch] by Matt Domsch <Matt_Domsch@dell.com>
+ *   Copyright 2000,2001,2002 Dell Computer Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * TODO:
+ *
+ * Changelog:
+ * Mon  Jan 14 2002 Matt Domsch <Matt_Domsch@dell.com>
+ * - based on code submitted to 2.5.2 kernel
+ *
+ ************************************************************/
+#define _FILE_OFFSET_BITS 64
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <endian.h>
+#include <netinet/in.h>
+#include <asm/byteorder.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "partx.h"
+#include "gpt.h"
+#include "crc32.h"
+
+#define BLKSSZGET  _IO(0x12,104)	/* get block device sector size */
+#define BLKGETLASTSECT  _IO(0x12,108)	/* get last sector of block device */
+#define BLKGETSIZE _IO(0x12,96)	/* return device 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;
+};
+
+static inline int
+efi_guidcmp (efi_guid_t left, efi_guid_t right)
+{
+	return memcmp (&left, &right, sizeof (efi_guid_t));
+}
+
+/**
+ * le_efi_guid_to_cpus()
+ * @guid
+ *
+ * Description: modifies @guid in situ
+ *
+ * This function converts a little endian efi_guid_t to the
+ * native cpu representation.  The EFI Spec. declares that all 
+ * on-disk structures are stored in little endian format.
+ */
+static void
+le_efi_guid_to_cpus (efi_guid_t * guid)
+{
+	__le32_to_cpus (guid->data1);
+	__le16_to_cpus (guid->data2);
+	__le16_to_cpus (guid->data3);
+	/* no need to change the rest. It's already an array of chars */
+	return;
+}
+
+/**
+ * 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);
+}
+
+/**
+ * le_part_attributes_to_cpus(): converts LE attributes to CPU type in situ
+ * @attributes - ptr to partition attributes
+ * 
+ * Description:  modifies attributes in situ, returns nothing.
+ * Converts a little endian partition attributes struct to the
+ * native cpu representation.  Good for reading attributes off of a disk.
+ */
+static void
+le_part_attributes_to_cpus (gpt_entry_attributes * a)
+{
+	uint64_t *b = (uint64_t *) a;
+	*b = __le64_to_cpu (*b);
+}
+
+/**
+ * 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_record[i].sys_type ==
+		    EFI_PMBR_OSTYPE_EFI_GPT) {
+			found = 1;
+			break;
+		}
+	}
+	return (signature && found);
+}
+
+static int
+get_sector_size (int fd)
+{
+	int rc, sector_size = 512;
+	rc = ioctl (fd, BLKSSZGET, &sector_size);
+	if (rc)
+		sector_size = 512;
+	return sector_size;
+}
+
+/**
+ * _get_num_sectors()
+ * @fd - open file descriptor
+ *  
+ * Description:
+ *  returns last LBA value on success, 0 on error
+ *  Try getting BLKGETSIZE64 and BLKSSZGET first,
+ *  then BLKGETSIZE if necessary.
+ */
+static uint64_t
+_get_num_sectors (int fd)
+{
+	uint64_t sectors=0;
+	int rc;
+
+	rc = ioctl(fd, BLKGETSIZE64, &sectors);
+	if (!rc)
+		return sectors;
+
+        sectors=0;
+        rc = ioctl(fd, BLKGETSIZE, &sectors);
+        if (rc)
+                return 0;
+
+	return sectors;
+}
+
+/**
+ * last_lba(): return number of last logical block of device
+ * @fd - open file descriptor
+ * 
+ * Description: Returns last LBA value on success, 0 on error.
+ * This is stored (by sd and ide-geometry) in
+ *  the part[0] entry for this disk, and is the number of
+ *  physical sectors available on the disk.
+ */
+
+static uint64_t
+last_lba (int fd)
+{
+	int rc;
+	uint64_t sectors = 0;
+	struct stat s;
+	memset (&s, 0, sizeof (s));
+	rc = fstat (fd, &s);
+	if (rc == -1) {
+		perror ("stat");
+		return 0;
+	}
+
+	if (S_ISBLK (s.st_mode)) {
+		sectors = _get_num_sectors (fd);
+	} 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 int
+read_lastoddsector (int fd, void *buffer)
+{
+	struct blkdev_ioctl_param ioctl_param;
+	int rc;
+
+	ioctl_param.block = 0;	/* read the last sector */
+	ioctl_param.content_length = get_sector_size (fd);
+	ioctl_param.block_contents = buffer;
+
+	rc = ioctl (fd, BLKGETLASTSECT, &ioctl_param);
+	if (rc == -1)
+		return -1;
+	return ioctl_param.content_length;
+}
+
+/**
+ * read_lba(): Read bytes from disk, starting at given LBA
+ * @fd - open file descriptor to the disk
+ * @lba
+ * @buffer
+ * @size_t
+ *
+ * Description:  Reads @count bytes from @bdev into @buffer.
+ * Returns number of bytes read on success, 0 on error.
+ * Read last block ioctl 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.
+  */
+static size_t
+read_lba (int fd, uint64_t lba, uint8_t * buffer, size_t count)
+{
+
+	size_t bytesread;
+	unsigned int blocksize = get_sector_size (fd);
+	off_t offset;
+	uint64_t lastlba = last_lba (fd);
+
+	if (!buffer || !count)
+		return 0;
+
+	offset = lseek (fd, lba * blocksize, SEEK_SET);
+	if (offset == (off_t) - 1) {
+		perror ("seek");
+		return 0;
+	}
+
+	bytesread = read (fd, buffer, count);
+	/* 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 && !(lastlba & 1) && lba == lastlba) {
+		bytesread = read_lastoddsector (fd, buffer);
+	}
+
+	return bytesread;
+}
+
+/**
+ * alloc_read_gpt_entries(): reads partition entries from disk
+ * @fd - open file descriptor
+ * @gpt - GPT header
+ * 
+ * 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)
+{
+	uint32_t i, j;
+	size_t count;
+	gpt_entry *pte;
+	if (!gpt)
+		return NULL;
+
+	count = gpt->num_partition_entries * gpt->sizeof_partition_entry;
+	if (!count)
+		return NULL;
+	pte = malloc (count);
+	if (!pte)
+		return NULL;
+	memset (pte, 0, count);
+
+	if (read_lba (fd, gpt->partition_entry_lba, (uint8_t *) pte,
+		      count) < count) {
+		free (pte);
+		return NULL;
+	}
+	/* Fixup endianness */
+	for (i = 0; i < gpt->num_partition_entries; i++) {
+		le_efi_guid_to_cpus (&pte[i].partition_type_guid);
+		le_efi_guid_to_cpus (&pte[i].unique_partition_guid);
+		__le64_to_cpus (pte[i].starting_lba);
+		__le64_to_cpus (pte[i].ending_lba);
+		le_part_attributes_to_cpus (&pte[i].attributes);
+		for (j = 0; j < (72 / sizeof (efi_char16_t)); j++) {
+			__le16_to_cpus ((uint16_t) (pte[i].partition_name[j]));
+		}
+	}
+
+	return pte;
+}
+
+/**
+ * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk
+ * @fd - open file descriptor
+ * @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 = malloc (sizeof (gpt_header));
+	if (!gpt)
+		return NULL;
+	memset (gpt, 0, sizeof (gpt_header));
+
+	if (read_lba (fd, lba, (uint8_t *) gpt,
+		      sizeof (gpt_header)) < sizeof (gpt_header)) {
+		free (gpt);
+		return NULL;
+	}
+
+	/* Fixup endianness */
+	__le64_to_cpus (gpt->signature);
+	__le32_to_cpus (gpt->revision);
+	__le32_to_cpus (gpt->header_size);
+	__le32_to_cpus (gpt->header_crc32);
+	__le32_to_cpus (gpt->reserved1);
+	__le64_to_cpus (gpt->my_lba);
+	__le64_to_cpus (gpt->alternate_lba);
+	__le64_to_cpus (gpt->first_usable_lba);
+	__le64_to_cpus (gpt->last_usable_lba);
+	le_efi_guid_to_cpus (&gpt->disk_guid);
+	__le64_to_cpus (gpt->partition_entry_lba);
+	__le32_to_cpus (gpt->num_partition_entries);
+	__le32_to_cpus (gpt->sizeof_partition_entry);
+	__le32_to_cpus (gpt->partition_entry_array_crc32);
+
+	return gpt;
+}
+
+/**
+ * is_gpt_valid() - tests one GPT header and PTEs for validity
+ * @fd - open file descriptor
+ * @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)
+{
+	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 ((*gpt)->signature != GPT_HEADER_SIGNATURE) {
+		free (*gpt);
+		*gpt = NULL;
+		return 0;
+	}
+
+	/* Check the GUID Partition Table CRC */
+	origcrc = (*gpt)->header_crc32;
+	(*gpt)->header_crc32 = 0;
+	crc = efi_crc32 ((const unsigned char *) (*gpt), (*gpt)->header_size);
+
+	if (crc != origcrc) {
+		free (*gpt);
+		*gpt = NULL;
+		return 0;
+	}
+	(*gpt)->header_crc32 = origcrc;
+
+	/* Check that the my_lba entry points to the LBA that contains
+	 * the GUID Partition Table */
+	if ((*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 ((const unsigned char *) (*ptes),
+			 (*gpt)->num_partition_entries *
+			 (*gpt)->sizeof_partition_entry);
+
+	if (crc != (*gpt)->partition_entry_array_crc32) {
+		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 (pgpt->my_lba != agpt->alternate_lba) {
+		fprintf (stderr,
+			 "GPT:Primary header LBA != Alt. header alternate_lba\n");
+		fprintf (stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
+			 pgpt->my_lba, agpt->alternate_lba);
+		error_found++;
+	}
+	if (pgpt->alternate_lba != agpt->my_lba) {
+		fprintf (stderr,
+			 "GPT:Primary header alternate_lba != Alt. header my_lba\n");
+		fprintf (stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
+			 pgpt->alternate_lba, agpt->my_lba);
+		error_found++;
+	}
+	if (pgpt->first_usable_lba != agpt->first_usable_lba) {
+		fprintf (stderr, "GPT:first_usable_lbas don't match.\n");
+		fprintf (stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
+			 pgpt->first_usable_lba, agpt->first_usable_lba);
+		error_found++;
+	}
+	if (pgpt->last_usable_lba != agpt->last_usable_lba) {
+		fprintf (stderr, "GPT:last_usable_lbas don't match.\n");
+		fprintf (stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
+			 pgpt->last_usable_lba, 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 (pgpt->num_partition_entries != agpt->num_partition_entries) {
+		fprintf (stderr, "GPT:num_partition_entries don't match: "
+			 "0x%x != 0x%x\n",
+			 pgpt->num_partition_entries,
+			 agpt->num_partition_entries);
+		error_found++;
+	}
+	if (pgpt->sizeof_partition_entry != agpt->sizeof_partition_entry) {
+		fprintf (stderr,
+			 "GPT:sizeof_partition_entry values don't match: "
+			 "0x%x != 0x%x\n", pgpt->sizeof_partition_entry,
+			 agpt->sizeof_partition_entry);
+		error_found++;
+	}
+	if (pgpt->partition_entry_array_crc32 !=
+	    agpt->partition_entry_array_crc32) {
+		fprintf (stderr,
+			 "GPT:partition_entry_array_crc32 values don't match: "
+			 "0x%x != 0x%x\n", pgpt->partition_entry_array_crc32,
+			 agpt->partition_entry_array_crc32);
+		error_found++;
+	}
+	if (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",
+			 pgpt->alternate_lba, lastlba);
+		error_found++;
+	}
+
+	if (agpt->my_lba != lastlba) {
+		fprintf (stderr,
+			 "GPT:Alternate GPT header not at the end of the disk.\n");
+		fprintf (stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
+			 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 - open file descriptor
+ * @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)
+{
+	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);
+	/* Check the Primary GPT */
+	good_pgpt = is_gpt_valid (fd, GPT_PRIMARY_PARTITION_TABLE_LBA,
+				  &pgpt, &pptes);
+	if (good_pgpt) {
+		/* Primary GPT is OK, check the alternate and warn if bad */
+		good_agpt = is_gpt_valid (fd, pgpt->alternate_lba,
+					  &agpt, &aptes);
+		if (!good_agpt) {
+			fprintf (stderr,
+				 "Alternate GPT is invalid, using primary GPT.\n");
+		}
+
+		compare_gpts (pgpt, agpt, lastlba);
+
+		*gpt = pgpt;
+		*ptes = pptes;
+		if (agpt)
+			free (agpt);
+		if (aptes)
+			free (aptes);
+	} /* if primary is valid */
+	else {
+		/* Primary GPT is bad, check the Alternate GPT */
+		good_agpt = is_gpt_valid (fd, lastlba, &agpt, &aptes);
+		if (good_agpt) {
+			/* Primary is bad, alternate is good.
+			   Return values from the alternate and warn.
+			 */
+			fprintf (stderr,
+				 "Primary GPT is invalid, using alternate GPT.\n");
+			*gpt = agpt;
+			*ptes = aptes;
+		}
+	}
+
+	/* Now test for valid PMBR */
+	/* This will be added to the EFI Spec. per Intel after v1.02. */
+	if (good_pgpt || good_agpt) {
+		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);
+		}
+		if (good_pmbr)
+			return 1;
+		else {
+			fprintf (stderr,
+				 " Warning: Disk has a valid GPT signature but invalid PMBR.\n");
+			fprintf (stderr,
+				 "  Assuming this disk is *not* a GPT disk anymore.\n");
+			fprintf (stderr, "  Use GNU Parted to correct disk.\n");
+		}
+	}
+
+	/* Both primary and alternate GPTs are bad, and/or PMBR is invalid.
+	 * This isn't our disk, return 0.
+	 */
+	if (pgpt) {
+		free (pgpt);
+		pgpt = NULL;
+	}
+	if (agpt) {
+		free (agpt);
+		agpt = NULL;
+	}
+	if (pptes) {
+		free (pptes);
+		pptes = NULL;
+	}
+	if (aptes) {
+		free (aptes);
+		aptes = NULL;
+	}
+	return 0;
+}
+
+/**
+ * add_gpt_partitions()
+ * @fd
+ * @all - slice with start/size of whole disk
+ *
+ * Description: Create devices for each entry in the GUID Partition Table
+ * Entries.
+ *
+ * We do not create a Linux partition for GPT, but
+ * only for the actual data partitions.
+ * Returns:
+ * -1 if unable to read the partition table
+ *  0 if this isn't our partition table
+ *  1 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;
+	efi_guid_t unusedGuid = UNUSED_ENTRY_GUID;
+
+	if (!find_valid_gpt (fd, &gpt, &ptes) || !gpt || !ptes) {
+		if (gpt)
+			free (gpt);
+		if (ptes)
+			free (ptes);
+		return 0;
+	}
+
+	for (i = 0; i < gpt->num_partition_entries && i < ns; i++) {
+		if (!efi_guidcmp (unusedGuid, ptes[i].partition_type_guid)) {
+			sp[n].start = 0;
+			sp[n].size = 0;
+			n++;
+		} else {
+			sp[n].start = ptes[i].starting_lba;
+			sp[n].size = ptes[i].ending_lba;
+			n++;
+		}
+	}
+	free (ptes);
+	free (gpt);
+	return n;
+}
+
+/*
+ * 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 -BurNp --exclude-from=/home/mdomsch/excludes util-linux-2.11n/partx/gpt.h util-linux/partx/gpt.h
--- util-linux-2.11n/partx/gpt.h	Wed Dec 31 18:00:00 1969
+++ util-linux/partx/gpt.h	Wed Jan 16 22:11:51 2002
@@ -0,0 +1,132 @@
+/************************************************************
+ * EFI GUID Partition Table
+ * Per Intel EFI Specification v1.02
+ * http://developer.intel.com/technology/efi/efi.htm
+ *
+ * By Matt Domsch <Matt_Domsch@dell.com>  Fri Sep 22 22:15:56 CDT 2000  
+ *   Copyright 2000,2001 Dell Computer Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ * 
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ ************************************************************/
+
+#ifndef GPT_H_INCLUDED
+#define GPT_H_INCLUDED
+
+#include <inttypes.h>
+#include "partx.h"
+#include "dos.h"
+
+typedef struct {
+	uint32_t data1;
+	uint16_t data2;
+	uint16_t data3;
+	uint8_t data4[8];
+} __attribute__ ((packed)) efi_guid_t;
+
+typedef uint16_t efi_char16_t;
+
+#define MSDOS_MBR_SIGNATURE 0xaa55
+#define EFI_PMBR_OSTYPE_EFI 0xEF
+#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
+
+#define GPT_BLOCK_SIZE 512
+#define GPT_HEADER_SIGNATURE 0x5452415020494645L
+#define GPT_HEADER_REVISION_V1 0x00010000
+#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
+
+#define UNUSED_ENTRY_GUID    \
+    ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
+#define PARTITION_SYSTEM_GUID \
+((efi_guid_t) { 0xC12A7328, 0xF81F, 0x11d2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
+#define LEGACY_MBR_PARTITION_GUID \
+    ((efi_guid_t) { 0x024DEE41, 0x33E7, 0x11d3, { 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
+#define PARTITION_MSFT_RESERVED_GUID \
+    ((efi_guid_t) { 0xE3C9E316, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
+#define PARTITION_BASIC_DATA_GUID \
+    ((efi_guid_t) { 0xEBD0A0A2, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
+#define PARTITION_LINUX_RAID_GUID \
+    ((efi_guid_t) { 0xa19d880f, 0x05fc, 0x4d3b, { 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e  }})
+#define PARTITION_LINUX_SWAP_GUID \
+    ((efi_guid_t) { 0x0657fd6d, 0xa4ab, 0x43c4, { 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f  }})
+#define PARTITION_LINUX_LVM_GUID \
+    ((efi_guid_t) { 0xe6d6d379, 0xf507, 0x44c2, { 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
+
+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;
+
+typedef struct _legacy_mbr {
+	uint8_t boot_code[440];
+	uint32_t unique_mbr_signature;
+	uint16_t unknown;
+	struct partition partition_record[4];
+	uint16_t signature;
+} __attribute__ ((packed)) legacy_mbr;
+
+/* Functions */
+extern 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 -BurNp --exclude-from=/home/mdomsch/excludes util-linux-2.11n/partx/partx.c util-linux/partx/partx.c
--- util-linux-2.11n/partx/partx.c	Wed Mar 22 16:25:34 2000
+++ util-linux/partx/partx.c	Wed Jan 16 17:05:38 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,7 +72,10 @@ 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);
@@ -98,6 +105,7 @@ main(int argc, char **argv){
 	int ret = 0;
 
 	initpts();
+	init_crc32();
 
 	lower = upper = 0;
 	type = device = diskdevice = NULL;
@@ -256,8 +264,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 -BurNp --exclude-from=/home/mdomsch/excludes util-linux-2.11n/partx/partx.h util-linux/partx/partx.h
--- util-linux-2.11n/partx/partx.h	Tue Mar 21 15:54:58 2000
+++ util-linux/partx/partx.h	Tue Jan 15 17:17:26 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 */
