diff options
author | Karel Zak <kzak@redhat.com> | 2006-12-07 00:25:54 +0100 |
---|---|---|
committer | Karel Zak <kzak@redhat.com> | 2006-12-07 00:25:54 +0100 |
commit | 1d4ad1decc539c9729b592e6050460d6487c95f4 (patch) | |
tree | c158c5f5baf15ea4bab5c05b2f6e2bdaca332c29 /partx | |
parent | ffc4374869b9ac10539a3c18e13b29d1b0c64484 (diff) | |
download | util-linux-old-1d4ad1decc539c9729b592e6050460d6487c95f4.tar.gz |
Imported from util-linux-2.11q tarball.
Diffstat (limited to 'partx')
-rw-r--r-- | partx/Makefile | 3 | ||||
-rw-r--r-- | partx/crc32.c | 393 | ||||
-rw-r--r-- | partx/crc32.h | 19 | ||||
-rw-r--r-- | partx/dos.c | 27 | ||||
-rw-r--r-- | partx/dos.h | 13 | ||||
-rw-r--r-- | partx/efi.h | 57 | ||||
-rw-r--r-- | partx/gpt.c | 630 | ||||
-rw-r--r-- | partx/gpt.h | 131 | ||||
-rw-r--r-- | partx/partx.c | 26 | ||||
-rw-r--r-- | partx/partx.h | 7 | ||||
-rw-r--r-- | partx/unixware.c | 4 |
11 files changed, 1289 insertions, 21 deletions
diff --git a/partx/Makefile b/partx/Makefile index 39237e01..9f9a9dbe 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 00000000..42d803d1 --- /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 00000000..a4505b84 --- /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 b32801e0..7b61d0b0 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 00000000..429f3d39 --- /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 00000000..fcf27409 --- /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 00000000..bf90fdeb --- /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, §or_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, §ors); + 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 00000000..d0a81f5f --- /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 212f651b..f56c2d57 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 b96588a5..efaa0640 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 3b3f21e1..34cc226a 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 */ |