diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/include/parted/Makefile.am parted-1.4.7-gpt/include/parted/Makefile.am --- parted-1.4.7/include/parted/Makefile.am Mon Dec 4 13:12:47 2000 +++ parted-1.4.7-gpt/include/parted/Makefile.am Thu Jan 18 11:24:42 2001 @@ -6,6 +6,7 @@ exception.h \ filesys.h \ natmath.h \ + crc32.h \ parted.h noinst_HEADERS = disk_bsd.h \ @@ -13,5 +14,6 @@ disk_loop.h \ disk_mac.h \ disk_pc98.h \ + disk_gpt.h \ endian.h diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/include/parted/crc32.h parted-1.4.7-gpt/include/parted/crc32.h --- parted-1.4.7/include/parted/crc32.h Wed Dec 31 18:00:00 1969 +++ parted-1.4.7-gpt/include/parted/crc32.h Thu Jan 18 11:24:42 2001 @@ -0,0 +1,34 @@ +/* + libparted - a library for manipulating disk partitions + Copyright (C) 1998-2000 Free Software Foundation, Inc. + + crc32.h + + 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 _CRC32_H +#define _CRC32_H + +#include + +/* + * This computes a 32 bit CRC of the data in the buffer, and returns the CRC. + * The polynomial used is 0xedb88320. + */ + +extern __u32 crc32 (const void *buf, unsigned long len, __u32 seed); + +#endif /* _CRC32_H */ diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/include/parted/disk_gpt.h parted-1.4.7-gpt/include/parted/disk_gpt.h --- parted-1.4.7/include/parted/disk_gpt.h Wed Dec 31 18:00:00 1969 +++ parted-1.4.7-gpt/include/parted/disk_gpt.h Wed Jan 24 11:23:31 2001 @@ -0,0 +1,195 @@ +/* + libparted - a library for manipulating disk partitions + + Copyright (C) 2000-2001 Dell Computer Corporation + disk_gpt.[ch] by Matt Domsch + + 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 EFI_GPT_H +#define EFI_GPT_H + + +#include + +#define EFI_PMBR_OSTYPE_EFI 0xEF +#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE +#define MSDOS_MBR_SIGNATURE 0xaa55 +#define GUID_PT_BLOCK_SIZE 512 + + +#define GUID_PT_HEADER_SIGNATURE 0x5452415020494645 +#define GUID_PT_HEADER_REVISION_V1_02 0x00010200 +#define GUID_PT_HEADER_REVISION_V1_00 0x00010000 +#define GUID_PT_HEADER_REVISION_V0_99 0x00009900 + +typedef __u16 efi_char16_t; /* UNICODE character */ + +typedef struct { + __u32 data1; + __u16 data2; + __u16 data3; + __u8 data4[8]; +} __attribute__ ((packed)) efi_guid_t; + + +#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_RAID_GUID \ + ((efi_guid_t) { 0xa19d880f, 0x05fc, 0x4d3b, { 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }}) +#define PARTITION_SWAP_GUID \ + ((efi_guid_t) { 0x0657fd6d, 0xa4ab, 0x43c4, { 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }}) +#define PARTITION_LVM_GUID \ + ((efi_guid_t) { 0xe6d6d379, 0xf507, 0x44c2, { 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }}) +#define PARTITION_RESERVED_GUID \ + ((efi_guid_t) { 0x8da63339, 0x0007, 0x60c0, { 0xc4, 0x36, 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }}) + +typedef struct _GuidPartitionTableHeader_t { + __u64 Signature; + __u32 Revision; + __u32 HeaderSize; + __u32 HeaderCRC32; + __u32 Reserved1; + __u64 MyLBA; + __u64 AlternateLBA; + __u64 FirstUsableLBA; + __u64 LastUsableLBA; + efi_guid_t DiskGUID; + __u64 PartitionEntryLBA; + __u32 NumberOfPartitionEntries; + __u32 SizeOfPartitionEntry; + __u32 PartitionEntryArrayCRC32; + __u8 Reserved2[GUID_PT_BLOCK_SIZE - 92]; +} __attribute__ ((packed)) GuidPartitionTableHeader_t; + +typedef struct _GuidPartitionEntryAttributes_t { + __u64 RequiredToFunction:1; + __u64 Reserved:47; + __u64 GuidSpecific:16; +} __attribute__ ((packed)) GuidPartitionEntryAttributes_t; + +typedef struct _GuidPartitionEntry_t { + efi_guid_t PartitionTypeGuid; + efi_guid_t UniquePartitionGuid; + __u64 StartingLBA; + __u64 EndingLBA; + GuidPartitionEntryAttributes_t Attributes; + efi_char16_t PartitionName[72 / sizeof(efi_char16_t)]; +} __attribute__ ((packed)) GuidPartitionEntry_t; + + +/* + 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(GuidPartitionEntry_t)) + + +typedef struct _PartitionRecord_t { + __u8 BootIndicator; /* Not used by EFI firmware. Set to 0x80 to indicate that this + is the bootable legacy partition. */ + __u8 StartHead; /* Start of partition in CHS address, not used by EFI firmware. */ + __u8 StartSector; /* Start of partition in CHS address, not used by EFI firmware. */ + __u8 StartTrack; /* Start of partition in CHS address, not used by EFI firmware. */ + __u8 OSType; /* OS type. A value of 0xEF defines an EFI system partition. + Other values are reserved for legacy operating systems, and + allocated independently of the EFI specification. */ + __u8 EndHead; /* End of partition in CHS address, not used by EFI firmware. */ + __u8 EndSector; /* End of partition in CHS address, not used by EFI firmware. */ + __u8 EndTrack; /* End of partition in CHS address, not used by EFI firmware. */ + __u32 StartingLBA; /* Starting LBA address of the partition on the disk. Used by + EFI firmware to define the start of the partition. */ + __u32 SizeInLBA; /* Size of partition in LBA. Used by EFI firmware to determine + the size of the partition. */ +} __attribute__ ((packed)) PartitionRecord_t; + + +/* Protected Master Boot Record & Legacy MBR share same structure */ +/* Needs to be packed because the u16s force misalignment. */ + +typedef struct _LegacyMBR_t { + __u8 BootCode[440]; + __u32 UniqueMBRSignature; + __u16 Unknown; + PartitionRecord_t PartitionRecord[4]; + __u16 Signature; +} __attribute__ ((packed)) LegacyMBR_t; + + + + +#define EFI_GPT_PRIMARY_PARTITION_TABLE_LBA 1 + + +/* Parted has a PedDisk field disk_specific that we'll keep + our own useful info in. +*/ +typedef struct _GPTDiskData { + GuidPartitionTableHeader_t *pgpt; + GuidPartitionTableHeader_t *agpt; + GuidPartitionEntry_t *ptes; +} GPTDiskData; + +/* Parted has a PedPartition field disk_specific that we'll keep + our own useful info in. +*/ +typedef struct _GPTPartitionData { + GuidPartitionEntry_t * pte; +} GPTPartitionData; + + +#define GPT_NAME "GPT" + +#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 -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/Makefile.am parted-1.4.7-gpt/libparted/Makefile.am --- parted-1.4.7/libparted/Makefile.am Mon Jan 8 13:57:26 2001 +++ parted-1.4.7-gpt/libparted/Makefile.am Thu Jan 18 11:24:42 2001 @@ -15,12 +15,23 @@ llseek.c \ llseek.h \ natmath.c \ + crc32.c \ disk.c \ disk_bsd.c \ disk_dos.c \ disk_loop.c \ disk_mac.c \ - disk_pc98.c + disk_pc98.c \ + disk_gpt.c \ + device_scsi.c \ + device_scsi.h \ + sg_map.c \ + sg_map.h \ + sg_dd.c \ + sg_dd.h \ + sg_err.c \ + sg_err.h + libparted_la_LIBADD = fs_ext2/libext2.la \ fs_fat/libfat.la \ diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/crc32.c parted-1.4.7-gpt/libparted/crc32.c --- parted-1.4.7/libparted/crc32.c Wed Dec 31 18:00:00 1969 +++ parted-1.4.7-gpt/libparted/crc32.c Thu Jan 18 11:24:42 2001 @@ -0,0 +1,125 @@ +/* + * Dec 5, 2000 Matt Domsch + * - Copied crc32.c from the linux/drivers/net/cipe directory. + * - Now pass seed as an arg + * - changed unsigned long to __u32, added #include + * - changed len to be an unsigned long + * - changed crc32val to be a register + * - License remains unchanged! It's still GPL-compatable! + */ + + /* ============================================================= */ + /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */ + /* code or tables extracted from it, as desired without restriction. */ + /* */ + /* First, the polynomial itself and its table of feedback terms. The */ + /* polynomial is */ + /* 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 */ + /* */ + /* Note that we take it "backwards" and put the highest-order term in */ + /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ + /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ + /* the MSB being 1. */ + /* */ + /* Note that the usual hardware shift register implementation, which */ + /* is what we're using (we're merely optimizing it by doing eight-bit */ + /* chunks at a time) shifts bits into the lowest-order term. In our */ + /* implementation, that means shifting towards the right. Why do we */ + /* do it this way? Because the calculated CRC must be transmitted in */ + /* order from highest-order term to lowest-order term. UARTs transmit */ + /* characters in order from LSB to MSB. By storing the CRC this way, */ + /* we hand it to the UART in the order low-byte to high-byte; the UART */ + /* sends each low-bit to hight-bit; and the result is transmission bit */ + /* by bit from highest- to lowest-order term without requiring any bit */ + /* shuffling on our part. Reception works similarly. */ + /* */ + /* The feedback terms table consists of 256, 32-bit entries. Notes: */ + /* */ + /* The table can be generated at runtime if desired; code to do so */ + /* is shown later. It might not be obvious, but the feedback */ + /* terms simply represent the results of eight shift/xor opera- */ + /* tions for all combinations of data and CRC register values. */ + /* */ + /* The values must be right-shifted by eight bits by the "updcrc" */ + /* logic; the shift must be unsigned (bring in zeroes). On some */ + /* hardware you could probably optimize the shift in assembler by */ + /* using byte-swap instructions. */ + /* polynomial $edb88320 */ + /* */ + /* -------------------------------------------------------------------- */ + +#include + +static __u32 crc32_tab[] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL + }; + +/* Return a 32-bit CRC of the contents of the buffer. */ + +__u32 +crc32(const void *buf, unsigned long len, __u32 seed) +{ + unsigned long i; + register __u32 crc32val; + const unsigned char *s = buf; + + crc32val = seed; + for (i = 0; i < len; i ++) + { + crc32val = + crc32_tab[(crc32val ^ s[i]) & 0xff] ^ + (crc32val >> 8); + } + return crc32val; +} diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/device.c parted-1.4.7-gpt/libparted/device.c --- parted-1.4.7/libparted/device.c Tue Jan 9 12:28:22 2001 +++ parted-1.4.7-gpt/libparted/device.c Thu Jan 18 11:24:42 2001 @@ -41,6 +41,7 @@ #include #include #include +#include "device_scsi.h" #include @@ -828,6 +829,20 @@ PED_ASSERT (!dev->external_mode, return 0); PED_ASSERT (buffer != NULL, return 0); + + /* Kludge. This is necessary to read/write the last + block of an odd-sized SCSI disk, until 2.5.x kernel fixes. + This is only used by disk_gpt.c, and only to read/write + one sector, so we don't have to be fancy. + */ + + if (dev->type == PED_DEVICE_SCSI && + (dev->length & 1) && + (count == 1) && + start == dev->length - 1) { + return ped_device_read_scsi(dev, buffer, start, count); + } + while (1) { if (ped_device_seek (dev, start)) break; @@ -946,6 +961,19 @@ return 0; else return 1; + } + + /* Kludge. This is necessary to read/write the last + block of an odd-sized SCSI disk, until 2.5.x kernel fixes. + This is only used by disk_gpt.c, and only to read/write + one sector, so we don't have to be fancy. + */ + + if (dev->type == PED_DEVICE_SCSI && + (dev->length & 1) && + (count == 1) && + start == dev->length - 1) { + return ped_device_write_scsi(dev, buffer, start, count); } while (1) { diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/device_scsi.c parted-1.4.7-gpt/libparted/device_scsi.c --- parted-1.4.7/libparted/device_scsi.c Wed Dec 31 18:00:00 1969 +++ parted-1.4.7-gpt/libparted/device_scsi.c Thu Jan 18 11:24:42 2001 @@ -0,0 +1,102 @@ +/* + libparted - a library for manipulating disk partitions + Copyright (C) 1998-2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include + +#include +#include"sg_map.h" +#include"sg_dd.h" + +static const char * +sg_from_sd(const char *sd) +{ + int i; + for (i=0; itype == PED_DEVICE_SCSI, return 0); + PED_ASSERT(buffer != NULL, return 0); + PED_ASSERT(count == 1, return 0); + + if (!sg_to_sd_map_made) make_sg_to_sd_map(); + + sg = sg_from_sd(dev->path); + if (!sg) return 0; + + // printf("sg=%s\n", sg); + /* Must open RDRW because we write the command to the disk + then read the results */ + if ((sg_fd = open(sg, O_RDWR)) < 0) + return 0; + + rc = sg_read(sg_fd, (unsigned char *)buffer, count, start, + dev->sector_size, &diop); + + close(sg_fd); + return !rc; +} + +int +ped_device_write_scsi (PedDevice* dev, const void* buffer, PedSector start, + PedSector count) +{ + char *sg = NULL; + extern int sg_to_sd_map_made; + int rc; + int sg_fd, diop = 0; + + // printf("in ped_device_write_scsi()\n"); + PED_ASSERT(dev != NULL, return 0); + PED_ASSERT(dev->type == PED_DEVICE_SCSI, return 0); + PED_ASSERT(buffer != NULL, return 0); + PED_ASSERT(count == 1, return 0); + + if (!sg_to_sd_map_made) make_sg_to_sd_map(); + sg = sg_from_sd(dev->path); + if (!sg) return 0; + + // printf("sg=%s\n", sg); + /* Must open RDRW because we write the command to the disk + then read the results */ + if ((sg_fd = open(sg, O_RDWR)) < 0) + return 0; + + rc = sg_write(sg_fd, (unsigned char *)buffer, count, start, + dev->sector_size, &diop); + + close(sg_fd); + return !rc; + +} diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/device_scsi.h parted-1.4.7-gpt/libparted/device_scsi.h --- parted-1.4.7/libparted/device_scsi.h Wed Dec 31 18:00:00 1969 +++ parted-1.4.7-gpt/libparted/device_scsi.h Thu Jan 18 11:24:42 2001 @@ -0,0 +1,28 @@ +/* + libparted - a library for manipulating disk partitions + Copyright (C) 1998-2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "parted/device.h" + +int +ped_device_read_scsi (PedDevice* dev, const void* buffer, PedSector start, + PedSector count); +int +ped_device_write_scsi (PedDevice* dev, const void* buffer, PedSector start, + PedSector count); + diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/disk.c parted-1.4.7-gpt/libparted/disk.c --- parted-1.4.7/libparted/disk.c Mon Jan 8 10:49:15 2001 +++ parted-1.4.7-gpt/libparted/disk.c Thu Jan 18 11:32:50 2001 @@ -174,6 +174,7 @@ disk->dev = dev; disk->type = disk_type; disk->update_mode = 0; + disk->disk_specific = NULL; disk->part_list = ped_partition_new ( disk, PED_PARTITION_FREESPACE, NULL, @@ -581,6 +582,7 @@ part->type = type; part->part_list = NULL; part->fs_type = fs_type; + part->disk_specific = NULL; return part; @@ -599,6 +601,8 @@ PedPartition* part; PED_ASSERT (disk != NULL, return NULL); + PED_ASSERT (disk->type != NULL, return NULL); + PED_ASSERT (disk->type->ops != NULL, return NULL); PED_ASSERT (disk->type->ops->partition_new != NULL, return NULL); supports_extended = ped_disk_type_check_feature (disk->type, @@ -1314,10 +1318,10 @@ PED_ASSERT (part != NULL, return 0); #ifdef VERBOSE - printf ("ped_disk_add_partition (dev=\"%s\", start=%d, end=%d," + printf ("ped_disk_add_partition (dev=\"%s\", start=%llx, end=%llx," " type=%x)\n", - disk->dev->path, (int) part->geom.start, (int) part->geom.end, - (int) part->system); + disk->dev->path, part->geom.start, part->geom.end, + part->type); #endif if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED) diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/disk_dos.c parted-1.4.7-gpt/libparted/disk_dos.c --- parted-1.4.7/libparted/disk_dos.c Tue Jan 9 12:29:52 2001 +++ parted-1.4.7-gpt/libparted/disk_dos.c Mon Jan 22 11:42:31 2001 @@ -232,6 +232,12 @@ return 0; } + /* If this is a GPT disk, fail here */ + for (i = 0; i < 4; i++) { + if (part_table.partitions[i].type == 0xEE) + return 0; + } + /* HACK: it's impossible to tell PC98 and msdos disk labels apart. * Someone made the signatures the same (very clever). Since * PC98 has some idiosyncracies with it's boot-loader, it's detection diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/disk_gpt.c parted-1.4.7-gpt/libparted/disk_gpt.c --- parted-1.4.7/libparted/disk_gpt.c Wed Dec 31 18:00:00 1969 +++ parted-1.4.7-gpt/libparted/disk_gpt.c Wed Jan 24 11:47:09 2001 @@ -0,0 +1,1738 @@ +/* + libparted - a library for manipulating disk partitions + + Copyright (C) 2000-2001 Dell Computer Corporation + disk_gpt.[ch] by Matt Domsch + + 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 +*/ + +/* + TODO: + - Make partition labels get/set properly +*/ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#if ENABLE_NLS +# define _(String) gettext (String) +#else +# define _(String) (String) +#endif /* ENABLE_NLS */ + + +void ped_disk_gpt_init(); +void ped_disk_gpt_done(); + +static int gpt_probe(const PedDevice * dev); +static PedDisk *gpt_open(PedDevice * dev); +static PedDisk *gpt_create(PedDevice * dev); +static int gpt_clobber(PedDevice * dev); +static int gpt_close(PedDisk * disk); +static int gpt_read(PedDisk * disk); +static int gpt_write(PedDisk * disk); + + +static PedPartition *gpt_partition_new(const PedDisk *disk, + PedPartitionType part_type, + const PedFileSystemType* fs_type, + PedSector start, + PedSector end); +static void gpt_partition_destroy(PedPartition *part); +static int gpt_partition_set_flag(PedPartition *part, + PedPartitionFlag flag, + int state); +static int gpt_partition_get_flag(const PedPartition *part, + PedPartitionFlag flag); +static int gpt_partition_is_flag_available(const PedPartition * part, + PedPartitionFlag flag); +static void gpt_partition_set_name(PedPartition *part, + const char *name); +static const char * gpt_partition_get_name (const PedPartition * part); +static int gpt_partition_align(PedPartition * part, + const PedConstraint * constraint); +static int gpt_partition_enumerate(PedPartition * part); + +static int gpt_alloc_metadata(PedDisk * disk); +static int gpt_get_max_primary_partition_count(const PedDisk *disk); + +/* gpt private function */ +static PedDisk * gpt_new(PedDisk * disk); + +static PedDiskOps gpt_disk_ops = { + probe : gpt_probe, + open : gpt_open, + create : gpt_create, + clobber : gpt_clobber, + close : gpt_close, + read : gpt_read, + write : gpt_write, + partition_new : gpt_partition_new, + partition_destroy : gpt_partition_destroy, + partition_set_flag : gpt_partition_set_flag, + partition_get_flag : gpt_partition_get_flag, + partition_is_flag_available : gpt_partition_is_flag_available, + partition_set_name : gpt_partition_set_name, + partition_get_name : gpt_partition_get_name, + partition_align : gpt_partition_align, + partition_enumerate : gpt_partition_enumerate, + partition_set_extended_system : NULL, + alloc_metadata : gpt_alloc_metadata, + get_max_primary_partition_count : gpt_get_max_primary_partition_count + +}; + +static PedDiskType gpt_disk_type = { + next:NULL, + name:GPT_NAME, + ops:&gpt_disk_ops, + features: PED_DISK_TYPE_PARTITION_NAME +}; + + + +/************************************************************ + * efi_crc32() + * Requires: + * - a buffer of length len + * Modifies: nothing + * Returns: + * EFI-style CRC32 value for buf + * + * This function uses the crc32 function by Gary S. Brown, + * but seeds the function with ~0, and xor's with ~0 at the end. + ************************************************************/ + +static inline __u32 +efi_crc32(const void *buf, unsigned long len) +{ + return (crc32(buf, len, ~0L) ^ ~0L); +} + + +static inline int +IsLegacyMBRValid(LegacyMBR_t * mbr) +{ + return (mbr ? (mbr->Signature == MSDOS_MBR_SIGNATURE) : 0); +} + +static inline int +efi_guidcmp(efi_guid_t left, efi_guid_t right) +{ + return memcmp(&left, &right, sizeof(efi_guid_t)); +} + + +/************************************************************ + * LastLBA() + * Requires: + * - dev + * Modifies: nothing + * Returns: + * Last LBA value on success + * 0 on error + ************************************************************/ + + +static __u64 +LastLBA(const PedDevice * dev) +{ + __u64 lastlba; + PED_ASSERT(dev != NULL, return 0); + lastlba = dev->length - 1; + /* Kludge until either: + a) kernel can read/write last + block on an odd-sized disk, or + b) we use scsi-generic to do it. + */ + // if (!(lastlba & 1)) lastlba--; + return lastlba; +} + + + +/************************************************************ + * IsLBAValid() + * Requires: + * - dev + * - lba is the logical block address desired + * Modifies: nothing + * Returns: + * - 1 if true + * - 0 if false + ************************************************************/ + + + +static inline int +IsLBAValid(PedDevice *dev, __u64 lba) +{ + return (lba <= LastLBA(dev)); +} + + +/************************************************************ + * WriteLBA() + * Requires: + * - dev + * - lba is the logical block address desired + * - buffer is a buffer of size size into which data is read + * - size_t count is size of the read (in bytes) + * Modifies: + * - dev + * Returns: + * - 1 on success + * - 0 on error + ************************************************************/ + +static int +WriteLBA(PedDevice * dev, __u64 lba, void *buffer, size_t count) +{ + size_t blocks; + //printf("WriteLBA(lba=%llx, count=%llx)\n", lba, count); + PED_ASSERT(dev != NULL, return 0); + PED_ASSERT(dev->sector_size != 0, return 0); + blocks = count / dev->sector_size; + if (count % dev->sector_size) + blocks++; + return ped_device_write(dev, buffer, lba, blocks); +} + +/************************************************************ + * ReadLBA() + * Requires: + * - dev + * - lba is the logical block address desired + * - buffer is a buffer of size size into which data is read + * - size_t count is size of the read (in bytes) + * Modifies: + * - dev + * Returns: + * - 1 on success + * - 0 on error + ************************************************************/ + +static int +ReadLBA(const PedDevice * dev, __u64 lba, void *buffer, size_t count) +{ + size_t blocks; + PED_ASSERT(dev != NULL, return 0); + PED_ASSERT(dev->sector_size != 0, return 0); + //printf("ReadLBA(lba=%llx, count=%llx)\n", lba, count); + blocks = count / dev->sector_size; + if (count % dev->sector_size) + blocks++; + return ped_device_read(dev, buffer, lba, blocks); +} + + + +/************************************************************ + * ReadGuidPartitionEntries() + * Requires: + * - dev + * - lba is the Logical Block Address of the partition table + * - gpt is a buffer into which the GPT will be put + * Modifies: + * - dev + * - gpt + * Returns: + * pte on success + * NULL on error + * Notes: remember to free pte when you're done! + ************************************************************/ +static GuidPartitionEntry_t * +ReadGuidPartitionEntries(const PedDevice * dev, + GuidPartitionTableHeader_t * + gpt) +{ + GuidPartitionEntry_t *pte; + + PED_ASSERT(dev != NULL, return NULL); + PED_ASSERT(gpt != NULL, return NULL); + + pte = (GuidPartitionEntry_t *) + ped_malloc(gpt->NumberOfPartitionEntries * + gpt->SizeOfPartitionEntry); + + PED_ASSERT(pte != NULL, return NULL); + + memset(pte, 0, gpt->NumberOfPartitionEntries * + gpt->SizeOfPartitionEntry); + + + if (!ReadLBA(dev, gpt->PartitionEntryLBA, pte, + gpt->NumberOfPartitionEntries * + gpt->SizeOfPartitionEntry)) { + free(pte); + return NULL; + } + return pte; +} + +/************************************************************ + * WriteGuidPartitionEntries() + * Requires: + * - PedDevice *dev + * - gpt + * - pte is a buffer that will be written + * Modifies: + * - dev + * - gpt + * Returns: + * pte on success + * NULL on error + * Notes: remember to free pte when you're done! + ************************************************************/ +static GuidPartitionEntry_t * +WriteGuidPartitionEntries(PedDevice * dev, + GuidPartitionTableHeader_t * gpt, + GuidPartitionEntry_t *ptes) +{ + PED_ASSERT(gpt != NULL, return NULL); + PED_ASSERT(ptes != NULL, return NULL); + + if (!WriteLBA + (dev, gpt->PartitionEntryLBA, ptes, + gpt->NumberOfPartitionEntries * + gpt->SizeOfPartitionEntry)) return NULL; + return ptes; +} + + +static void +PrintGuidPartitionEntry(GuidPartitionEntry_t * pte, int i) +{ + efi_guid_t unused_guid = UNUSED_ENTRY_GUID; + char uuid_buffer[40]; + uuid_t uuid; + PED_ASSERT(pte != NULL, return); + if (!efi_guidcmp(pte->PartitionTypeGuid, unused_guid)) { + // printf("UNUSED_ENTRY_GUID\n"); + return; + } + printf("GUID Partition Entry %d:\n", i); + memcpy(uuid, &pte->PartitionTypeGuid, sizeof(uuid_t)); + uuid_unparse(uuid, uuid_buffer); + printf("\tPartitionTypeGuid : %s\n", uuid_buffer); + memcpy(uuid, &pte->UniquePartitionGuid, sizeof(uuid_t)); + uuid_unparse(uuid, uuid_buffer); + printf("\tUniquePartitionGuid : %s\n", uuid_buffer); + printf("\tStartingLBA : %llx\n", pte->StartingLBA); + printf("\tEndingLBA : %llx\n", pte->EndingLBA); + printf("\tAttributes : "); + printf("\tRequiredToFunction: %x", + pte->Attributes.RequiredToFunction); + printf("\tGuidSpecific: %x\n", + pte->Attributes.GuidSpecific); + + // printf("\tPartitionName : Unicode string.\n"); + return; +} + + +static void +PrintGuidPartitionTableHeader(GuidPartitionTableHeader_t * gpt) +{ + char uuid_buffer[40]; + uuid_t uuid; + printf("GUID Partition Table Header\n"); + PED_ASSERT(gpt != NULL, return); + printf("Signature : %llx\n", gpt->Signature); + printf("Revision : %x\n", gpt->Revision); + printf("HeaderSize : %x\n", gpt->HeaderSize); + printf("HeaderCRC32 : %x\n", gpt->HeaderCRC32); + printf("MyLBA : %llx\n", gpt->MyLBA); + printf("AlternateLBA : %llx\n", gpt->AlternateLBA); + printf("FirstUsableLBA : %llx\n", gpt->FirstUsableLBA); + printf("LastUsableLBA : %llx\n", gpt->LastUsableLBA); + memcpy(uuid, &gpt->DiskGUID, sizeof(uuid_t)); + uuid_unparse(uuid, uuid_buffer); + printf("DiskGUID : %s\n", uuid_buffer); + printf("PartitionEntryLBA : %llx\n", gpt->PartitionEntryLBA); + printf("NumberOfPartitionEntries : %x\n", + gpt->NumberOfPartitionEntries); + printf("SizeOfPartitionEntry : %x\n", gpt->SizeOfPartitionEntry); + printf("PartitionEntryArrayCRC32 : %x\n", + gpt->PartitionEntryArrayCRC32); return; +} + + +/************************************************************ + * ReadGuidPartitionTableHeader() + * Requires: + * - dev + * - lba is the Logical Block Address of the partition table + * Modifies: + * - dev + * Returns: + * GPTH on success + * NULL on error + ************************************************************/ +static GuidPartitionTableHeader_t * +ReadGuidPartitionTableHeader(const PedDevice * dev, + __u64 lba) +{ + GuidPartitionTableHeader_t *gpt; + PED_ASSERT(dev != NULL, return 0); + gpt = (GuidPartitionTableHeader_t *) + ped_malloc(sizeof(GuidPartitionTableHeader_t)); + if (!gpt) return NULL; + memset(gpt, 0, sizeof (*gpt)); + if (!ReadLBA(dev, lba, gpt, sizeof(GuidPartitionTableHeader_t))) { + free(gpt); + return NULL; + } + + return gpt; +} + +/************************************************************ + * WriteGuidPartitionTableHeader() + * Requires: + * - dev + * - lba is the Logical Block Address of the partition table + * - gpt is a buffer into which the GPT will be put + * Modifies: + * - dev + * Returns: + * 1 on success + * 0 on error + ************************************************************/ +static int +WriteGuidPartitionTableHeader(PedDevice *dev, + GuidPartitionTableHeader_t * gpt) +{ + PED_ASSERT(gpt != NULL, return 0); + if (!WriteLBA + (dev, gpt->MyLBA, gpt, + sizeof(GuidPartitionTableHeader_t))) return 0; + return 1; +} + + +/************************************************************ + * IsGuidPartitionTableValid() + * Requires: + * - dev + * - lba is the Logical Block Address of the partition table + * Modifies: + * - dev + * - gpt - reads data into gpt + * - ptes - reads data into ptes + * Returns: + * 1 if valid + * 0 on error + ************************************************************/ + + +static int +IsGuidPartitionTableValid(const PedDevice * dev, __u64 lba, + GuidPartitionTableHeader_t ** gpt, + GuidPartitionEntry_t ** ptes) +{ + int rc = 0; /* default to not valid */ + __u32 crc, origcrc; + PED_ASSERT(gpt != NULL, return 0); + PED_ASSERT(ptes != NULL, return 0); + // printf("IsGuidPartitionTableValid(%llx)\n", lba); + if (!(*gpt = ReadGuidPartitionTableHeader(dev, lba))) + return rc; + /* Check the GUID Partition Table Signature */ + if ((*gpt)->Signature != GUID_PT_HEADER_SIGNATURE) { + /* + printf("GUID Partition Table Header Signature is wrong: %llx != %llx\n", + (*gpt)->Signature, GUID_PT_HEADER_SIGNATURE); + */ + free(*gpt); + *gpt = NULL; + return rc; + } + + /* Check the GUID Partition Table Header CRC */ + origcrc = (*gpt)->HeaderCRC32; + (*gpt)->HeaderCRC32 = 0; + crc = efi_crc32(*gpt, (*gpt)->HeaderSize); + if (crc != origcrc) { + // printf( "GPTH CRC check failed, %x != %x.\n", origcrc, crc); + (*gpt)->HeaderCRC32 = origcrc; + PrintGuidPartitionTableHeader(*gpt); + free(*gpt); + *gpt = NULL; + return rc; + } + (*gpt)->HeaderCRC32 = origcrc; + /* Check that the MyLBA entry points to the LBA + that contains the GPT we read */ + if ((*gpt)->MyLBA != lba) { + // printf( "MyLBA %llx != lba %llx.\n", (*gpt)->MyLBA, lba); + free(*gpt); + *gpt = NULL; + return rc; + } + + if (!(*ptes = ReadGuidPartitionEntries(dev, *gpt))) { + free(*gpt); + *gpt = NULL; + return rc; + } + + + /* Check the GUID Partition Entry Array CRC */ + crc = efi_crc32(*ptes, (*gpt)->NumberOfPartitionEntries * + (*gpt)->SizeOfPartitionEntry); + if (crc != (*gpt)->PartitionEntryArrayCRC32) { + // printf("GUID Partitition Entry Array CRC check failed.\n"); + free(*gpt); + *gpt = NULL; + free(*ptes); + *ptes = NULL; + return rc; + } + + /* We're done, all's well */ + return 1; +} + +/************************************************************ + * CreateNewPMBR() + * Requires: + * - dev + * Modifies: + * - dev + * Returns: + * 1 on success + * 0 on error + ************************************************************/ + + +static int +CreateNewPMBR(PedDevice * dev) +{ + LegacyMBR_t pmbr; + memset(&pmbr, 0, sizeof(pmbr)); + pmbr.Signature = MSDOS_MBR_SIGNATURE; + pmbr.PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI_GPT; + pmbr.PartitionRecord[0].EndHead = 0xFF; + pmbr.PartitionRecord[0].EndSector = 0xFE; + pmbr.PartitionRecord[0].EndTrack = 0xFF; + pmbr.PartitionRecord[0].StartingLBA = 1; + pmbr.PartitionRecord[0].SizeInLBA = LastLBA(dev) + 1; + if (!WriteLBA(dev, 0, &pmbr, sizeof(pmbr))) { + + // printf("CreateNewPMBR(): Unable to create new PMBR.\n"); + return 0; + } + + return 1; + +} + + +#if 0 +static int +UpdateGuidPartition(PedPartition *part) +{ + GPTPartitionData *gpt_part_data; + PED_ASSERT(part != NULL, return -1); + PED_ASSERT(part->disk_specific != NULL, return 0); + + gpt_part_data = part->disk_specific; + PED_ASSERT(gpt_part_data->pte != NULL, return -1); + + gpt_part_data->pte->StartingLBA = part->geom.start; + gpt_part_data->pte->EndingLBA = part->geom.end; + gpt_part_data->pte->PartitionTypeGuid = PARTITION_BASIC_DATA_GUID; + + /* FIXME: need to change type to PARTITION_SYSTEM_GUID + or tag raid and lvm flags into attributes */ + + return 1; +} +#endif + +#if 0 +/*********************************** + * CreateDefaultMSRGuidPartition() + * + * Returns: 1 on success, 0 on failure + * + */ + + +static int +CreateDefaultMSRGuidPartition(GuidPartitionTableHeader_t * gpt, + GuidPartitionEntry_t * pte) +{ + __u64 size; + int i; + PED_ASSERT(gpt != NULL, return 0); + PED_ASSERT(pte != NULL, return 0); + + /* The rule is : + On drives < 16GB, MSR is 32MB. + On drives >= 16GB, MSR is 128MB. + */ + + /* This accounts for block size == 512 */ + if (gpt->LastUsableLBA < 16 * 1024 * 1024 * 2) + size = (16 * 1024 * 1024) / 512; + else + size = (128 * 1024 * 1024) / 512; + + i = CreateNextGuidPartition(gpt, pte, size); + if (i == -1) + return 0; + + pte[i].PartitionTypeGuid = PARTITION_MSFT_RESERVED_GUID; + return 1; +} + + +static int +CreateDefaultEFIGuidPartition(GuidPartitionTableHeader_t * gpt, + GuidPartitionEntry_t * pte) +{ + int i; + __u64 size; + PED_ASSERT(gpt != NULL, return 0); + PED_ASSERT(pte != NULL, return 0); + + + /* The rule is : + size = MAX(100MB, MIN(1% of physical disk, 1GB)) + */ + size = PED_MAX((100 * 1024 * 1024) / 512; + PED_MIN(gpt->LastUsableLBA / 100, + (1024 * 1024 * 1024) / 512)); + + i = CreateNextGuidPartition(gpt, pte, size); + if (i == -1) + return 0; + pte[i].PartitionTypeGuid = PARTITION_SYSTEM_GUID; + return 1; +} +#endif + +/************************************************************n + * UpdateGuidPartitionTableHeaders() + * Updates the CRC fields for both primary and alternate GPTs + * + */ +static int +UpdateGuidPartitionTableHeaders(GuidPartitionTableHeader_t *pgpt, + GuidPartitionTableHeader_t *agpt, + GuidPartitionEntry_t *ptes) +{ + + // printf("in UpdateGuidPartitionTableHeaders()\n"); + PED_ASSERT(pgpt != NULL, return 0); + PED_ASSERT(agpt != NULL, return 0); + PED_ASSERT(ptes != NULL, return 0); + + pgpt->PartitionEntryArrayCRC32 = + agpt->PartitionEntryArrayCRC32 = + efi_crc32(ptes, pgpt->NumberOfPartitionEntries * + pgpt->SizeOfPartitionEntry); + + pgpt->HeaderCRC32 = 0; + pgpt->HeaderCRC32 = efi_crc32(pgpt, pgpt->HeaderSize); + agpt->HeaderCRC32 = 0; + agpt->HeaderCRC32 = efi_crc32(agpt, agpt->HeaderSize); + return 1; +} + + + +static int +CreateNewGuidPartitionTableHeader(PedDevice *dev) +{ + __u64 size; + uuid_t uuid; + GuidPartitionTableHeader_t gpt, agpt; + GuidPartitionEntry_t ptes[GPT_DEFAULT_RESERVED_PARTITION_ENTRIES]; + int count; + + // printf("in CreateNewGuidPartitionTableHeader()\n"); + memset(&gpt, 0, sizeof(gpt)); + gpt.Signature = GUID_PT_HEADER_SIGNATURE; + gpt.Revision = GUID_PT_HEADER_REVISION_V1_02; + gpt.HeaderSize = 92; /* per 1.02 spec */ + gpt.MyLBA = 1; + gpt.AlternateLBA = LastLBA(dev); + gpt.FirstUsableLBA = (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE / + dev->sector_size) + 2; + gpt.LastUsableLBA = + gpt.AlternateLBA - + (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE / + dev->sector_size) - 1; + uuid_generate(uuid); + memcpy(&(gpt.DiskGUID), uuid, sizeof(uuid)); + gpt.PartitionEntryLBA = 2; + gpt.NumberOfPartitionEntries = GPT_DEFAULT_RESERVED_PARTITION_ENTRIES; + gpt.SizeOfPartitionEntry = sizeof(GuidPartitionEntry_t); + + memset(ptes, 0, + gpt.NumberOfPartitionEntries * gpt.SizeOfPartitionEntry); + + /* Fix up Alternate GPT */ + memcpy(&agpt, &gpt, sizeof(gpt)); + agpt.MyLBA = gpt.AlternateLBA; + agpt.AlternateLBA = gpt.MyLBA; + agpt.PartitionEntryLBA = agpt.MyLBA - + (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE / + dev->sector_size); + + if (!UpdateGuidPartitionTableHeaders(&gpt, &agpt, ptes)) + return 0; + + // printf("update successful\n"); + + /* Before the writes */ + /* Write PTH and PTEs */ + if (!WriteGuidPartitionTableHeader(dev, &gpt)) + return 0; + if (!WriteGuidPartitionEntries(dev, &gpt, ptes)) + return 0; + + + /* Write Alternate PTH & PTEs */ + if (!WriteGuidPartitionEntries(dev, &agpt, ptes)) + return 0; + if (!WriteGuidPartitionTableHeader(dev, &agpt)) + return 0; + + return 1; +} + + + +static int +CreateNewGPTDisk(PedDevice * dev) +{ + if (!CreateNewPMBR(dev)) + return 0; + if (!CreateNewGuidPartitionTableHeader(dev)) + return 0; + return 1; +} + + +/************************************************************ + * FixPrimaryGuidPartitionTable() + * Uses values from alternate GPT and puts them in primary GPT. + * Requires: + * pgpt, agpt, ptes. + * + * Modifies: + * pgpt + * + * Returns: + * 1 if valid + * 0 on error + ************************************************************/ + +static int +FixBrokenGuidPartitionTable(PedDevice *dev, + GuidPartitionTableHeader_t **badgpt, + GuidPartitionTableHeader_t *goodgpt, + GuidPartitionEntry_t *ptes) +{ + + PED_ASSERT(badgpt != NULL, return 0); + PED_ASSERT(goodgpt != NULL, return 0); + PED_ASSERT(ptes != NULL, return 0); + + *badgpt = (GuidPartitionTableHeader_t *) + ped_malloc(sizeof(GuidPartitionTableHeader_t)); + if (!*badgpt) return 0; + memset(*badgpt, 0, sizeof(**badgpt)); + + memcpy(*badgpt, goodgpt, sizeof(*goodgpt)); + + /* Change badgpt values */ + (*badgpt)->MyLBA = goodgpt->AlternateLBA; + (*badgpt)->AlternateLBA = goodgpt->MyLBA; + + + if ((*badgpt)->MyLBA == 1) + (*badgpt)->PartitionEntryLBA = (*badgpt)->MyLBA + 1; + else + (*badgpt)->PartitionEntryLBA = (*badgpt)->MyLBA - + (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE / + dev->sector_size); + + return UpdateGuidPartitionTableHeaders(*badgpt, goodgpt, ptes); +} + + + + +static void +PrintPartitionRecord(PartitionRecord_t * pr, int i) +{ + if (!pr) + return; + if (!(pr->OSType)) + return; + printf("Legacy Partition Record %d\n", i); + printf("\tBootInd %02x", pr->BootIndicator); + printf("\tSHead %02x", pr->StartHead); + printf("\tSSector %02x", pr->StartSector); + printf("\tSTrack %02x\n", pr->StartTrack); + printf("\tOSType %02x", pr->OSType); + printf("\tEHead %02x", pr->EndHead); + printf("\tESector %02x", pr->EndSector); + printf("\tETrack %02x\n", pr->EndTrack); + printf("\tStartingLBA : %x", pr->StartingLBA); + printf("\tSizeInLBA : %x\n", pr->SizeInLBA); + return; +} + +static void +PrintLegacyMBR(LegacyMBR_t * mbr) +{ + int i; + if (!mbr) + return; + if (!IsLegacyMBRValid(mbr)) { + printf("MBR is invalid.\n"); + return; + } + + printf("UniqueMBRSignature: %x\n", mbr->UniqueMBRSignature); + for (i = 0; i < 4; i++) + PrintPartitionRecord(&(mbr->PartitionRecord[i]), i); + printf("Signature: %x\n", mbr->Signature); + return; +} + + + +/************************************************************ + * FindValidGPT() + * Requires: + * - dev + * - pgpt is a GPTH if it's valid + * - agpt is a GPTH if it's valid + * - ptes is a PTE + * Modifies: + * - gpt & ptes + * Returns: + * 1 if valid + * 0 on error + ************************************************************/ +static int +FindValidGPT(const PedDevice * dev, + GuidPartitionTableHeader_t ** pgpt, + GuidPartitionTableHeader_t ** agpt, + GuidPartitionEntry_t ** ptes) +{ + int rc = 0; + GuidPartitionEntry_t *pptes = NULL, *aptes = NULL; + __u64 lastlba; + + PED_ASSERT(dev != NULL, return 0); + PED_ASSERT(pgpt != NULL, return 0); + PED_ASSERT(agpt != NULL, return 0); + PED_ASSERT(ptes != NULL, return 0); + + // printf("FindValidGPT()\n"); + lastlba = LastLBA(dev); + /* Check the Primary GPT */ + rc = IsGuidPartitionTableValid(dev, 1, pgpt, &pptes); + if (rc) { + /* Primary GPT is OK, check the alternate and warn if bad */ + rc = IsGuidPartitionTableValid(dev, (*pgpt)->AlternateLBA, + agpt, &aptes); + + if (!rc) { + *agpt = NULL; + printf("Alternate GPT is invalid, using primary GPT.\n"); + + } + if (aptes) free(aptes); + *ptes = pptes; + return 1; + } /* if primary is valid */ + else { + /* Primary GPT is bad, check the Alternate GPT */ + *pgpt = NULL; + rc = IsGuidPartitionTableValid(dev, lastlba, + agpt, &aptes); + if (rc) { + /* Primary is bad, alternate is good. + Return values from the alternate and warn. + */ + printf + ("Primary GPT is invalid, using alternate GPT.\n"); + *ptes = aptes; + return 1; + } + } + /* Both primary and alternate GPTs are bad. + * This isn't our disk, return 0. + */ + *pgpt = NULL; + *agpt = NULL; + *ptes = NULL; + return 0; +} + + +static void +PrintDiskInfo(PedDevice *dev) +{ + unsigned int i; + LegacyMBR_t mbr; + GuidPartitionTableHeader_t *pgpt = NULL, *agpt = NULL, *gpt = NULL; + GuidPartitionEntry_t *pte = NULL, zeropte; + + // printf("PrintDiskInfo()\n"); + memset(&zeropte, 0, sizeof(zeropte)); + if (!ReadLBA(dev, 0, &mbr, sizeof(mbr))) { + printf("PrintDiskInfo error: ReadLBA(mbr) error.\n"); + return; + } + PrintLegacyMBR(&mbr); + if (mbr.PartitionRecord[0].OSType == EFI_PMBR_OSTYPE_EFI_GPT) { + /* This is an EFI GPT disk */ + if (!ReadLBA(dev, 1, &pgpt, sizeof(*pgpt))) { + printf("PrintDiskInfo error: ReadLBA(gpt) error.\n"); + return; + } + printf("This is an EFI GPT disk.\n"); + if (FindValidGPT(dev, &pgpt, &agpt, &pte)) { + if (pgpt) gpt = pgpt; + else if (agpt) gpt = agpt; + } + else { + printf("GUID Partition Table is invalid.\n"); + return; + } + for (i = 0; pte && i < gpt->NumberOfPartitionEntries; i++) { + /* Partition entry is unused if all bytes are 0 */ + if (memcmp(&zeropte, &pte[i], sizeof(zeropte))) + PrintGuidPartitionEntry(&pte[i], i); + } + if (pgpt) free(pgpt); + if (agpt) free(agpt); + if (pte) free(pte); + } else { + printf("This is not an EFI GPT disk. Try using fdisk.\n"); + } + return; +} + + + + + + +void +ped_disk_gpt_init() +{ + PED_ASSERT(sizeof(GuidPartitionTableHeader_t) == 512, return); + PED_ASSERT(sizeof(GuidPartitionEntryAttributes_t) == 8, return); + PED_ASSERT(sizeof(GuidPartitionEntry_t) == 128, return); + + ped_register_disk_type(&gpt_disk_type); +} + +void +ped_disk_gpt_done() +{ + ped_unregister_disk_type(&gpt_disk_type); +} + +static int +gpt_probe(const PedDevice * dev) +{ + GuidPartitionTableHeader_t *pgpt = NULL, *agpt = NULL; + GuidPartitionEntry_t *ptes = NULL; + + PED_ASSERT(dev != NULL, return 0); + + // printf("gpt_probe()\n"); + + if (!ped_device_open((PedDevice *) dev)) + return 0; + + if (!(FindValidGPT(dev, &pgpt, &agpt, &ptes))) { + ped_device_close((PedDevice *) dev); + return 0; + } + + ped_device_close((PedDevice *) dev); + + if (pgpt) free(pgpt); + if (agpt) free(agpt); + if (ptes) free(ptes); + // printf("gpt_probe returning 1\n"); + return 1; +} + +static PedDisk * +gpt_open(PedDevice * dev) +{ + PedDisk *disk; + + // printf("gpt_open()\n"); + + PED_ASSERT(dev != NULL, return 0); + + if (!gpt_probe(dev)) + goto error; + + + ped_device_open((PedDevice *) dev); + + // printf("gpt_open() called ped_device_open()\n"); + disk = ped_disk_alloc(dev, &gpt_disk_type); + // printf("gpt_open called ped_disk_alloc()\n"); + + if (!disk) + goto error; + + // printf("gpt_open: ped_disk_alloc() succeeded\n"); + + // printf("gpt_open() calling gpt_read()\n"); + if (!gpt_read(disk)) + goto error_free_disk_specific; + + // printf("gpt_open returning disk\n"); + return disk; + + error_free_disk_specific: + ped_free(disk->disk_specific); + error_free_disk: + ped_free(disk); + error: + // printf("gpt_open() returning NULL\n"); + return NULL; +} + +static PedDisk * +gpt_create(PedDevice * dev) +{ + PedDisk *newdisk; + PED_ASSERT(dev != NULL, return 0); + + // printf("gpt_create()\n"); + if (!ped_device_open(dev)) + goto error; + + + CreateNewGPTDisk(dev); + + if (!ped_device_sync(dev)) + goto error_close_dev; + + ped_device_close(dev); + newdisk = gpt_open(dev); + return newdisk; + + error_close_dev: + ped_device_close(dev); + error: + return 0; +} + +static int +gpt_close(PedDisk * disk) +{ + // printf("in gpt_close()\n"); + PED_ASSERT(disk != NULL, return 0); + + ped_device_close(disk->dev); + ped_disk_delete_all(disk); + if (disk->disk_specific) ped_free(disk->disk_specific); + ped_free(disk); + return 1; +} + + + + + + +static int +gpt_read(PedDisk * disk) +{ + PedPartition *part; + unsigned int i; + GPTDiskData *gpt_disk_data; + GPTPartitionData *gpt_part_data; + PedConstraint* constraint_exact; + efi_guid_t unused = UNUSED_ENTRY_GUID; + + // printf("in gpt_read()\n"); + PED_ASSERT(disk != NULL, return 0); + PED_ASSERT(disk->dev != NULL, return 0); + + + ped_disk_delete_all(disk); + + // printf("gpt_read(): ped_disk_delete_all() returned.\n"); + + if (!disk->disk_specific) gpt_new(disk); + PED_ASSERT(disk->disk_specific != NULL, return 0); + gpt_disk_data = disk->disk_specific; + + + if (!FindValidGPT(disk->dev, &(gpt_disk_data->pgpt), &(gpt_disk_data->agpt), &(gpt_disk_data->ptes))) + return 0; + + /* If one of the gpts are broken, fix it. */ + if (!gpt_disk_data->pgpt) { + FixBrokenGuidPartitionTable(disk->dev, + &gpt_disk_data->pgpt, + gpt_disk_data->agpt, + gpt_disk_data->ptes); + } + else if (!gpt_disk_data->agpt) { + FixBrokenGuidPartitionTable(disk->dev, + &gpt_disk_data->agpt, + gpt_disk_data->pgpt, + gpt_disk_data->ptes); + } + + for (i = 0; i < gpt_disk_data->pgpt->NumberOfPartitionEntries; i++) { + + if (!efi_guidcmp(gpt_disk_data->ptes[i].PartitionTypeGuid, + unused)) continue; + + // printf("calling ped_partition_alloc() in gpt_read(), i=%u\n", i); + // PrintGuidPartitionEntry(&gpt_disk_data->ptes[i], i); + part = ped_partition_alloc(disk, PED_PARTITION_PRIMARY, NULL, + gpt_disk_data->ptes[i].StartingLBA, + gpt_disk_data->ptes[i].EndingLBA); + if (!part) + return 0; + + part->num = i+1; + + gpt_part_data = part->disk_specific = + ped_malloc(sizeof(GPTPartitionData)); + if (!gpt_part_data) { + ped_free(part); + return 0; + } + memset(gpt_part_data, 0, sizeof(*gpt_part_data)); + + gpt_part_data->pte = &(gpt_disk_data->ptes[i]); + + // printf("handling constraints\n"); + constraint_exact = ped_constraint_exact (&part->geom); + if (!ped_disk_add_partition(disk, part, constraint_exact)) { + ped_free(gpt_part_data); + ped_free(part); + // printf("gpt_read() returning 0 after ped_disk_add_partition()\n"); + return 0; + } + ped_constraint_destroy (constraint_exact); + + } + // printf("gpt_read() returning 1\n"); + return 1; +} + + +static int +gpt_write(PedDisk * disk) +{ + + GPTDiskData *gpt_disk_data; + PedPartition *part = NULL; + + // printf("!!!!!in gpt_write()\n"); + PED_ASSERT(disk != NULL, return 0); + PED_ASSERT(disk->dev != NULL, return 0); + PED_ASSERT(disk->disk_specific != NULL, return 0); + gpt_disk_data = disk->disk_specific; + + if (!CreateNewPMBR(disk->dev)) return 0; + + UpdateGuidPartitionTableHeaders(gpt_disk_data->pgpt, + gpt_disk_data->agpt, + gpt_disk_data->ptes); + + /* Write PTH and PTEs */ + if (!WriteGuidPartitionTableHeader(disk->dev, gpt_disk_data->pgpt)) + return 0; + if (!WriteGuidPartitionEntries(disk->dev, gpt_disk_data->pgpt, gpt_disk_data->ptes)) + return 0; + + + /* Write Alternate PTH & PTEs */ + if (!WriteGuidPartitionEntries(disk->dev, gpt_disk_data->agpt, gpt_disk_data->ptes)) + return 0; + if (!WriteGuidPartitionTableHeader(disk->dev, gpt_disk_data->agpt)) + return 0; + + + + + if (!ped_device_sync(disk->dev)) + return 0; + + return 1; +} + + + +static int +add_metadata_part(PedDisk * disk, PedPartitionType type, PedSector start, + PedSector length) +{ + PedPartition *new_part; + PedConstraint * constraint_exact; + PED_ASSERT(disk != NULL, return 0); + + + // printf("calling ped_partition_new() in add_metadata_part()\n"); + new_part = + ped_partition_new(disk, type | PED_PARTITION_METADATA, NULL, + start, start + length - 1); + if (!new_part) + goto error; + + constraint_exact = ped_constraint_exact (&new_part->geom); + + if (!ped_disk_add_partition(disk, new_part, constraint_exact)) + goto error_destroy_new_part; + + return 1; + + error_destroy_new_part: + ped_partition_destroy(new_part); + error: + return 0; +} + +static PedPartition * +gpt_partition_new(const PedDisk *disk, + PedPartitionType part_type, + const PedFileSystemType* fs_type, + PedSector start, + PedSector end) +{ + unsigned int i; + uuid_t uuid; + efi_guid_t unused_entry_guid = UNUSED_ENTRY_GUID; + GPTDiskData *gpt_disk_data; + GPTPartitionData *gpt_part_data; + PedPartition *part; + + PED_ASSERT(disk != NULL, return NULL); + + + part = ped_partition_alloc (disk, part_type, fs_type, start, end); + if (!part) return NULL; + + if (part_type != PED_PARTITION_PRIMARY) + return part; + + if (!ped_disk_check_overlap(disk, part)) { + ped_exception_throw ( + PED_EXCEPTION_ERROR, + PED_EXCEPTION_CANCEL, + _("The new partition overlaps with another " + "partition.")); + ped_free(part); + return NULL; + } + + PED_ASSERT(disk->disk_specific != NULL, return NULL); + + gpt_disk_data = disk->disk_specific; + // printf("in gpt_partition_new(s=%llx, e=%llx t=%d)\n", start, end, part_type); + + + PED_ASSERT(gpt_disk_data->pgpt != NULL, return NULL); + PED_ASSERT(gpt_disk_data->agpt != NULL, return NULL); + PED_ASSERT(gpt_disk_data->ptes != NULL, return NULL); + + + for (i = 0; i < gpt_disk_data->pgpt->NumberOfPartitionEntries; i++) { + if (!efi_guidcmp + (gpt_disk_data->ptes[i].PartitionTypeGuid, unused_entry_guid)) { + break; + } + } + /* No unused entries */ + if (i == gpt_disk_data->pgpt->NumberOfPartitionEntries){ + ped_free(part); + return NULL; + } + + // printf("Found unused entry at i=%u\n", i); + part->num = i + 1; + gpt_disk_data->ptes[i].StartingLBA = part->geom.start; + gpt_disk_data->ptes[i].EndingLBA = part->geom.end; + uuid_generate(uuid); + memcpy(&(gpt_disk_data->ptes[i].UniquePartitionGuid), uuid, sizeof(uuid)); + + gpt_disk_data->ptes[i].PartitionTypeGuid = PARTITION_BASIC_DATA_GUID; + + if (fs_type && fs_type->name && !strcmp(fs_type->name, "linux-swap")) + gpt_disk_data->ptes[i].PartitionTypeGuid = + PARTITION_SWAP_GUID; + + + gpt_part_data = part->disk_specific = + ped_malloc(sizeof(GPTPartitionData)); + if (!gpt_part_data) return part; + memset(gpt_part_data, 0, sizeof(*gpt_part_data)); + + gpt_part_data->pte = &(gpt_disk_data->ptes[i]); + + return part; +} + +static void +gpt_partition_destroy(PedPartition *part) +{ + GPTPartitionData *gpt_part_data; + + PED_ASSERT(part != NULL, return); + // printf("in gpt_partition_destroy(type=%x)\n", part->type); + + if (part->type != PED_PARTITION_PRIMARY) + return; + + PED_ASSERT(part->disk_specific != NULL, return); + gpt_part_data = part->disk_specific; + if (gpt_part_data->pte) + memset(gpt_part_data->pte, 0, sizeof(*(gpt_part_data->pte))); + + ped_free(part->disk_specific); + part->disk_specific = NULL; + ped_free(part); + // printf("returning from gpt_partition_destroy()\n"); +} + +/********************************************************** + * Allocate metadata partitions for the GPTH and PTES. + * + */ +static int +_alloc_metadata_unknown(PedDisk * disk) +{ + __u64 pte_reserved_blocks; + PED_ASSERT(disk != NULL, return 0); + PED_ASSERT(disk->dev != NULL, return 0); + + pte_reserved_blocks = + (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE / + disk->dev->sector_size); + + + // printf("in _alloc_metadata_unknown()\n"); + /* metadata at the start of the disk includes the MBR */ + // printf("adding metadata at start of the disk.\n"); + if (!add_metadata_part(disk, PED_PARTITION_PRIMARY, + 0, + 1 + 1 + pte_reserved_blocks)) + return 0; + + /* metadata at the end of the disk */ + // printf("adding metadata at end of the disk.\n"); + if (!add_metadata_part(disk, PED_PARTITION_PRIMARY, + LastLBA(disk->dev) - + pte_reserved_blocks, + 1 + pte_reserved_blocks)) + return 0; + + return 1; +} + + +/********************************************************** + * Allocate metadata partitions for the GPTH and PTES + * when we know the actual metadata size + */ +static int +_alloc_metadata_known(PedDisk * disk) +{ + int i; + PedSector gptlength, pteslength = 0; + GPTDiskData *gpt_disk_data; + + // printf("in _alloc_metadata_known()\n"); + PED_ASSERT(disk != NULL, return 0); + PED_ASSERT(disk->dev != NULL, return 0); + PED_ASSERT(disk->disk_specific != NULL, return 0); + gpt_disk_data = disk->disk_specific; + + /* allocate space for the header */ + gptlength = gpt_disk_data->pgpt->HeaderSize / disk->dev->sector_size; + if (gpt_disk_data->pgpt->HeaderSize % disk->dev->sector_size) + gptlength++; + /* allocate space for the ptes */ + pteslength = + (gpt_disk_data->pgpt->NumberOfPartitionEntries * + gpt_disk_data->pgpt->SizeOfPartitionEntry) / + disk->dev->sector_size; + if ((gpt_disk_data->pgpt->NumberOfPartitionEntries * + gpt_disk_data->pgpt->SizeOfPartitionEntry) % + disk->dev->sector_size) + pteslength++; + + /* metadata at the start of the disk includes the MBR */ + // printf("adding metadata at start of the disk.\n"); + if (!add_metadata_part(disk, PED_PARTITION_PRIMARY, + 0, 1 + gptlength + pteslength)) + return 0; + + /* metadata at the end of the disk */ + // printf("adding metadata at end of the disk.\n"); + if (!add_metadata_part(disk, PED_PARTITION_PRIMARY, + LastLBA(disk->dev) - gptlength - pteslength + 1, + gptlength + pteslength)) + return 0; + + return 1; +} + + + + +/********************************************************** + * Allocate metadata partitions for the GPTH and PTES. + * + */ +static int +gpt_alloc_metadata(PedDisk * disk) +{ + GPTDiskData *gpt_disk_data; + PED_ASSERT(disk != NULL, return 0); + PED_ASSERT(disk->dev != NULL, return 0); + + gpt_disk_data = disk->disk_specific; + + if (!gpt_disk_data || + !gpt_disk_data->pgpt || + !gpt_disk_data->agpt || + !gpt_disk_data->ptes) + return _alloc_metadata_unknown(disk); + + return _alloc_metadata_known(disk); +} + +/************************************************************ + * gpt_partition_enumerate() + * Requires: + * - part + * Modifies: + * - part->num + * Returns: + * 1 if valid + * 0 on error + * Actions: + * Does nothing, as the read/new/destroy functions maintain + * part->num. + * + * + ************************************************************/ +static int +gpt_partition_enumerate(PedPartition * part) +{ + return 1; +} + + +/************************************************************ + * gpt_clobber() + * Requires: + * - dev + * Modifies: + * - dev + * Returns: + * 1 if valid + * 0 on error + * Actions: + * This writes zeros to the PMBR and the primary and + * alternate GPTHs and PTEs. + ************************************************************/ +static int +gpt_clobber(PedDevice * dev) +{ + LegacyMBR_t pmbr; + GuidPartitionTableHeader_t gpt; + GuidPartitionEntry_t ptes[GPT_DEFAULT_RESERVED_PARTITION_ENTRIES]; + __u64 lastLBA, pte_reserved_blocks; + + + // printf("in gpt_clobber()\n"); + PED_ASSERT (dev != NULL, return 0); + PED_ASSERT (gpt_probe(dev), return 0); + + if (!ped_device_open(dev)) return 0; + + PED_ASSERT(dev->sector_size != 0, return 0); + pte_reserved_blocks = GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE / + dev->sector_size; + + + memset(&pmbr, 0, sizeof(pmbr)); + memset(&gpt, 0, sizeof(gpt)); + memset(ptes, 0, + GPT_DEFAULT_RESERVED_PARTITION_ENTRIES * + sizeof(GuidPartitionEntry_t)); + lastLBA = LastLBA(dev); + + if (!WriteLBA(dev, 0, &pmbr, sizeof(pmbr))) { + printf("gpt_clobber(): Unable to write empty PMBR.\n"); + return 0; + } + if (!WriteLBA(dev, 1, &gpt, sizeof(gpt))) { + printf("gpt_clobber(): Unable to write empty PGPTH.\n"); + return 0; + } + if (!WriteLBA(dev, 2, ptes, sizeof(ptes))) { + printf("gpt_clobber(): Unable to write empty PPTES.\n"); + return 0; + } + if (!WriteLBA(dev, lastLBA-pte_reserved_blocks, ptes, + sizeof(ptes))) { + printf("gpt_clobber(): Unable to write empty APTES.\n"); + return 0; + } + if (!WriteLBA(dev, lastLBA, &gpt, sizeof(gpt))) { + printf("gpt_clobber(): Unable to write empty AGPTH.\n"); + return 0; + } + return 1; +} + + +static int +gpt_partition_set_flag(PedPartition *part, + PedPartitionFlag flag, + int state) +{ + GPTPartitionData *gpt_part_data; + PED_ASSERT(part != NULL, return 0); + PED_ASSERT(part->disk_specific != NULL, return 0); + gpt_part_data = part->disk_specific; + PED_ASSERT(gpt_part_data->pte != NULL, return 0); + + + switch (flag) { + case PED_PARTITION_RAID: + if (state) + gpt_part_data->pte->PartitionTypeGuid = + PARTITION_RAID_GUID; + else + gpt_part_data->pte->PartitionTypeGuid = + PARTITION_BASIC_DATA_GUID; + break; + case PED_PARTITION_LVM: + if (state) + gpt_part_data->pte->PartitionTypeGuid = + PARTITION_LVM_GUID; + else + gpt_part_data->pte->PartitionTypeGuid = + PARTITION_BASIC_DATA_GUID; + + break; + case PED_PARTITION_BOOT: + if (state) + gpt_part_data->pte->PartitionTypeGuid = + PARTITION_SYSTEM_GUID; + else + gpt_part_data->pte->PartitionTypeGuid = + PARTITION_BASIC_DATA_GUID; + + break; + case PED_PARTITION_LBA: + if (!state) return 0; + break; + case PED_PARTITION_HIDDEN: + default: + return 0; + } + + if (part->fs_type && part->fs_type->name && + !strcmp(part->fs_type->name, "linux-swap")) + gpt_part_data->pte->PartitionTypeGuid = + PARTITION_SWAP_GUID; + + + return 1; +} + +static int +gpt_partition_get_flag(const PedPartition *part, + PedPartitionFlag flag) +{ + GPTPartitionData *gpt_part_data = NULL; + PED_ASSERT(part->disk_specific != NULL, return 0); + gpt_part_data = part->disk_specific; + + switch (flag) { + case PED_PARTITION_RAID: + return (!efi_guidcmp(gpt_part_data->pte->PartitionTypeGuid, + PARTITION_RAID_GUID)); + case PED_PARTITION_LVM: + return (!efi_guidcmp(gpt_part_data->pte->PartitionTypeGuid, + PARTITION_LVM_GUID)); + case PED_PARTITION_BOOT: + return (!efi_guidcmp(gpt_part_data->pte->PartitionTypeGuid, + PARTITION_SYSTEM_GUID)); + case PED_PARTITION_LBA: + return 1; + case PED_PARTITION_HIDDEN: + default: + return 0; + } + return 0; +} + +static int +gpt_partition_is_flag_available(const PedPartition * part, + PedPartitionFlag flag) +{ + switch (flag) { + case PED_PARTITION_RAID: + case PED_PARTITION_LVM: + case PED_PARTITION_LBA: + case PED_PARTITION_BOOT: + return 1; + case PED_PARTITION_HIDDEN: + default: + return 0; + } + return 0; +} + +static void +gpt_partition_set_name(PedPartition *part, + const char *name) +{ + unsigned int i; + GPTPartitionData *gpt_part_data = NULL; + PED_ASSERT(part->disk_specific != NULL, return); + gpt_part_data = part->disk_specific; + + if (!gpt_part_data->pte) return; + + memset(gpt_part_data->pte->PartitionName, 0, sizeof(gpt_part_data->pte->PartitionName)); + + for (i=0; i < (72 / sizeof(efi_char16_t)) && i < strlen(name); i++) { + gpt_part_data->pte->PartitionName[i] = name[i]; + } + return; +} +static const char * +gpt_partition_get_name (const PedPartition * part) +{ + /* The name is stored in Unicode in the GPT entry */ + char *name; + unsigned int i, namelen = (72 / sizeof(efi_char16_t)); + GPTPartitionData *gpt_part_data = NULL; + PED_ASSERT(part->disk_specific != NULL, return 0); + gpt_part_data = part->disk_specific; + + if (!gpt_part_data->pte) return NULL; + + name = ped_malloc(namelen); + if (!name) return NULL; + + memset(name, 0, namelen); + + for (i=0; i < namelen ; i++) { + name[i] = gpt_part_data->pte->PartitionName[i]; + } + + return name; +} + + +static int +gpt_get_max_primary_partition_count(const PedDisk *disk) +{ + int rc = GPT_DEFAULT_RESERVED_PARTITION_ENTRIES; /* 128 */ + GPTDiskData *gpt_disk_data; + PED_ASSERT(disk != NULL, return 0); + gpt_disk_data = disk->disk_specific; + + if (gpt_disk_data && gpt_disk_data->pgpt) + rc = gpt_disk_data->pgpt->NumberOfPartitionEntries; + return rc; +} + +/* There are no alignment issues with GPT */ +static int +gpt_partition_align(PedPartition * part, + const PedConstraint * constraint) +{ + // printf("in gpt_partition_align()\n"); + return 1; +} + +static PedDisk * +gpt_new(PedDisk * disk) +{ + // printf("gpt_new(%p)\n", disk); + PED_ASSERT(disk != NULL, return NULL); + if (disk->disk_specific) return disk; + + disk->disk_specific = ped_malloc(sizeof(GPTDiskData)); + PED_ASSERT(disk->disk_specific != NULL, return NULL); + memset(disk->disk_specific, 0, sizeof(GPTDiskData)); + return disk; +} + + +/* + * 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 -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/fs_ext2/interface.c parted-1.4.7-gpt/libparted/fs_ext2/interface.c --- parted-1.4.7/libparted/fs_ext2/interface.c Mon Dec 4 13:12:47 2000 +++ parted-1.4.7-gpt/libparted/fs_ext2/interface.c Thu Jan 18 11:45:14 2001 @@ -31,6 +31,7 @@ #include #include #include +#include #include "ext2.h" #include "parted_io.h" @@ -342,6 +343,15 @@ if (strcmp (disk_type->name, BSD_NAME) == 0) { BSDPartitionData* bsd_data = part->disk_specific; bsd_data->type = 0x8; + return 1; + } + + if (strcmp (disk_type->name, GPT_NAME) == 0) { + GPTPartitionData *gpt_part_data = part->disk_specific; + PED_ASSERT(gpt_part_data != NULL, return 0); + PED_ASSERT(gpt_part_data->pte != NULL, return 0); + gpt_part_data->pte->PartitionTypeGuid = + PARTITION_BASIC_DATA_GUID; return 1; } diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/fs_fat/fat.c parted-1.4.7-gpt/libparted/fs_fat/fat.c --- parted-1.4.7/libparted/fs_fat/fat.c Mon Dec 4 13:12:47 2000 +++ parted-1.4.7-gpt/libparted/fs_fat/fat.c Thu Jan 18 11:42:08 2001 @@ -22,6 +22,7 @@ #include #include #include +#include #include "fat.h" #include "calc.h" @@ -751,6 +752,15 @@ else strcpy (mac_data->system_name, "FAT"); mac_data->status = 0x33; + return 1; + } + + if (strcmp (disk_type->name, GPT_NAME) == 0) { + GPTPartitionData *gpt_part_data = part->disk_specific; + PED_ASSERT(gpt_part_data != NULL, return 0); + PED_ASSERT(gpt_part_data->pte != NULL, return 0); + gpt_part_data->pte->PartitionTypeGuid = + PARTITION_BASIC_DATA_GUID; return 1; } diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/fs_hfs/hfs.c parted-1.4.7-gpt/libparted/fs_hfs/hfs.c --- parted-1.4.7/libparted/fs_hfs/hfs.c Fri Jan 5 07:30:56 2001 +++ parted-1.4.7-gpt/libparted/fs_hfs/hfs.c Thu Jan 18 11:44:07 2001 @@ -25,6 +25,7 @@ #include #include #include +#include #include #if ENABLE_NLS @@ -151,6 +152,15 @@ strcpy (mac_data->system_name, "Apple_HFS"); mac_data->status |= 0x7f; } + return 1; + } + + if (strcmp (disk_type->name, GPT_NAME) == 0) { + GPTPartitionData *gpt_part_data = part->disk_specific; + PED_ASSERT(gpt_part_data != NULL, return 0); + PED_ASSERT(gpt_part_data->pte != NULL, return 0); + gpt_part_data->pte->PartitionTypeGuid = + PARTITION_BASIC_DATA_GUID; return 1; } diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/fs_linux_swap/linux_swap.c parted-1.4.7-gpt/libparted/fs_linux_swap/linux_swap.c --- parted-1.4.7/libparted/fs_linux_swap/linux_swap.c Fri Jan 5 07:31:23 2001 +++ parted-1.4.7-gpt/libparted/fs_linux_swap/linux_swap.c Thu Jan 18 11:24:42 2001 @@ -28,6 +28,7 @@ #include #include #include +#include #include #if ENABLE_NLS @@ -565,6 +566,15 @@ if (strcmp (disk_type->name, BSD_NAME) == 0) { BSDPartitionData* bsd_data = part->disk_specific; bsd_data->type = 0x1; + return 1; + } + + if (strcmp (disk_type->name, GPT_NAME) == 0) { + GPTPartitionData* gpt_part_data = part->disk_specific; + PED_ASSERT(gpt_part_data != NULL, return 0); + PED_ASSERT(gpt_part_data->pte != NULL, return 0); + gpt_part_data->pte->PartitionTypeGuid = + PARTITION_SWAP_GUID; return 1; } diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/fs_ntfs/ntfs.c parted-1.4.7-gpt/libparted/fs_ntfs/ntfs.c --- parted-1.4.7/libparted/fs_ntfs/ntfs.c Fri Jan 5 07:29:47 2001 +++ parted-1.4.7-gpt/libparted/fs_ntfs/ntfs.c Thu Jan 18 11:45:18 2001 @@ -25,6 +25,7 @@ #include #include #include +#include #include #if ENABLE_NLS @@ -147,6 +148,15 @@ else strcpy (mac_data->system_name, "Apple_UNIX_SVR2"); mac_data->status = 0x33; + return 1; + } + + if (strcmp (disk_type->name, GPT_NAME) == 0) { + GPTPartitionData *gpt_part_data = part->disk_specific; + PED_ASSERT(gpt_part_data != NULL, return 0); + PED_ASSERT(gpt_part_data->pte != NULL, return 0); + gpt_part_data->pte->PartitionTypeGuid = + PARTITION_BASIC_DATA_GUID; return 1; } diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/fs_reiserfs/reiserfs.c parted-1.4.7-gpt/libparted/fs_reiserfs/reiserfs.c --- parted-1.4.7/libparted/fs_reiserfs/reiserfs.c Fri Jan 5 07:30:13 2001 +++ parted-1.4.7-gpt/libparted/fs_reiserfs/reiserfs.c Thu Jan 18 11:42:34 2001 @@ -25,6 +25,7 @@ #include #include #include +#include #include #if ENABLE_NLS @@ -181,6 +182,15 @@ else strcpy (mac_data->system_name, "Apple_UNIX_SVR2"); mac_data->status = 0x33; + return 1; + } + + if (strcmp (disk_type->name, GPT_NAME) == 0) { + GPTPartitionData *gpt_part_data = part->disk_specific; + PED_ASSERT(gpt_part_data != NULL, return 0); + PED_ASSERT(gpt_part_data->pte != NULL, return 0); + gpt_part_data->pte->PartitionTypeGuid = + PARTITION_BASIC_DATA_GUID; return 1; } diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/libparted.c parted-1.4.7-gpt/libparted/libparted.c --- parted-1.4.7/libparted/libparted.c Thu Jan 11 13:03:16 2001 +++ parted-1.4.7-gpt/libparted/libparted.c Thu Jan 18 11:24:42 2001 @@ -65,6 +65,7 @@ ped_disk_pc98_init (); ped_disk_mac_init (); ped_disk_bsd_init (); + ped_disk_gpt_init (); } static void @@ -102,6 +103,7 @@ ped_disk_loop_done (); ped_disk_mac_done (); ped_disk_bsd_done (); + ped_disk_gpt_done (); } static void diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/sg_dd.c parted-1.4.7-gpt/libparted/sg_dd.c --- parted-1.4.7/libparted/sg_dd.c Wed Dec 31 18:00:00 1969 +++ parted-1.4.7-gpt/libparted/sg_dd.c Thu Jan 18 11:24:42 2001 @@ -0,0 +1,781 @@ + /* + libparted - a library for manipulating disk partitions + Copyright (C) 1998-2000 Free Software Foundation, Inc. + + 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 _XOPEN_SOURCE 500 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* cope with silly includes */ +#include +typedef unsigned char u_char; /* horrible, for scsi.h */ +#include "sg_err.h" + +#if 0 +#include "sg_llseek.h" +#endif + +/* A utility program for the Linux OS SCSI generic ("sg") device driver. +* Copyright (C) 1999, 2000 D. Gilbert and P. Allworth +* 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, or (at your option) +* any later version. + + This program is a specialization of the Unix "dd" command in which + either the input or the output file is a scsi generic device or a + raw device. The block size ('bs') is assumed to be 512 if not given. + This program complains if 'ibs' or 'obs' are given with a value + that differs from 'bs' (or the default 512). + If 'if' is not given or 'if=-' then stdin is assumed. If 'of' is + not given or 'of=-' then stdout assumed. Multipliers: + 'c','C' *1 'b','B' *512 'k' *1024 'K' *1000 + 'm' *(1024^2) 'M' *(1000^2) 'g' *(1024^3) 'G' *(1000^3) + + A non-standard argument "bpt" (blocks per transfer) is added to control + the maximum number of blocks in each transfer. The default value is 128. + For example if "bs=512" and "bpt=32" then a maximum of 32 blocks (16KB + in this case) is transferred to or from the sg device in a single SCSI + command. + + This version should compile with Linux sg drivers with version numbers + >= 30000 . + + Version 5.11 20001220 +*/ + +#define DEF_BLOCK_SIZE 512 +#define DEF_BLOCKS_PER_TRANSFER 128 + +// #define SG_DEBUG + +#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */ +#define READ_CAP_REPLY_LEN 8 +#define DEF_TIMEOUT 40000 /* 40,000 millisecs == 40 seconds */ + +#ifndef RAW_MAJOR +#define RAW_MAJOR 255 /*unlikey value */ +#endif + +#define FT_OTHER 0 /* filetype other than sg or raw device */ +#define FT_SG 1 /* filetype is sg char device */ +#define FT_RAW 2 /* filetype is raw char device */ + +static int sum_of_resids = 0; + +static int dd_count = -1; +static int in_full = 0; +static int in_partial = 0; +static int out_full = 0; +static int out_partial = 0; + +static void install_handler (int sig_num, void (*sig_handler) (int sig)) +{ + struct sigaction sigact; + sigaction (sig_num, NULL, &sigact); + if (sigact.sa_handler != SIG_IGN) + { + sigact.sa_handler = sig_handler; + sigemptyset (&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction (sig_num, &sigact, NULL); + } +} + +static void print_stats() +{ + if (0 != dd_count) + fprintf(stderr, " remaining block count=%d\n", dd_count); + fprintf(stderr, "%d+%d records in\n", in_full, in_partial); + fprintf(stderr, "%d+%d records out\n", out_full, out_partial); +} + +static void interrupt_handler(int sig) +{ + struct sigaction sigact; + + sigact.sa_handler = SIG_DFL; + sigemptyset (&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction (sig, &sigact, NULL); + fprintf(stderr, "Interrupted by signal,"); + print_stats (); + kill (getpid (), sig); +} + +static void siginfo_handler(int sig) +{ + fprintf(stderr, "Progress report, continuing ...\n"); + print_stats (); +} + +static int dd_filetype(const char * filename) +{ + struct stat st; + + if (stat(filename, &st) < 0) + return FT_OTHER; + if (S_ISCHR(st.st_mode)) { + if (RAW_MAJOR == major(st.st_rdev)) + return FT_RAW; + else if (SCSI_GENERIC_MAJOR == major(st.st_rdev)) + return FT_SG; + } + return FT_OTHER; +} + +static void usage() +{ + fprintf(stderr, "Usage: " + "sg_dd [if=] [skip=] [of=] [seek=]\n" + " [bs=] [bpt=] [count=]" + " [dio=]\n" + " either 'if' or 'of' must be a sg or raw device\n" + " 'bpt' is blocks_per_transfer (default is 128)\n" + " 'dio' is direct IO, 1->attempt, 0->indirect IO (def)\n"); +} + +/* Return of 0 -> success, -1 -> failure, 2 -> try again */ +static int read_capacity(int sg_fd, int * num_sect, int * sect_sz) +{ + int res; + unsigned char rcCmdBlk [10] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + unsigned char rcBuff[READ_CAP_REPLY_LEN]; + unsigned char sense_b[64]; + sg_io_hdr_t io_hdr; + + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof(rcCmdBlk); + io_hdr.mx_sb_len = sizeof(sense_b); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = sizeof(rcBuff); + io_hdr.dxferp = rcBuff; + io_hdr.cmdp = rcCmdBlk; + io_hdr.sbp = sense_b; + io_hdr.timeout = DEF_TIMEOUT; + + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { + perror("read_capacity (SG_IO) error"); + return -1; + } + res = sg_err_category3(&io_hdr); + if (SG_ERR_CAT_MEDIA_CHANGED == res) + return 2; /* probably have another go ... */ + else if (SG_ERR_CAT_CLEAN != res) { + sg_chk_n_print3("read capacity", &io_hdr); + return -1; + } + *num_sect = 1 + ((rcBuff[0] << 24) | (rcBuff[1] << 16) | + (rcBuff[2] << 8) | rcBuff[3]); + *sect_sz = (rcBuff[4] << 24) | (rcBuff[5] << 16) | + (rcBuff[6] << 8) | rcBuff[7]; + return 0; +} + +/* -1 -> unrecoverable error, 0 -> successful, 1 -> recoverable (ENOMEM), + 2 -> try again */ +int sg_read(int sg_fd, unsigned char * buff, unsigned int blocks, unsigned int from_block, + int bs, int * diop) +{ + unsigned char rdCmd[10] = {0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + unsigned char senseBuff[SENSE_BUFF_LEN]; + sg_io_hdr_t io_hdr; + int res; + + rdCmd[2] = (unsigned char)((from_block >> 24) & 0xFF); + rdCmd[3] = (unsigned char)((from_block >> 16) & 0xFF); + rdCmd[4] = (unsigned char)((from_block >> 8) & 0xFF); + rdCmd[5] = (unsigned char)(from_block & 0xFF); + rdCmd[7] = (unsigned char)((blocks >> 8) & 0xff); + rdCmd[8] = (unsigned char)(blocks & 0xff); + + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof(rdCmd); + io_hdr.cmdp = rdCmd; + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = bs * blocks; + io_hdr.dxferp = buff; + io_hdr.mx_sb_len = SENSE_BUFF_LEN; + io_hdr.sbp = senseBuff; + io_hdr.timeout = DEF_TIMEOUT; + io_hdr.pack_id = from_block; + if (diop && *diop) + io_hdr.flags |= SG_FLAG_DIRECT_IO; + + while (((res = write(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) && + (EINTR == errno)) + ; + if (res < 0) { + if (ENOMEM == errno) + return 1; + perror("reading (wr) on sg device, error"); + return -1; + } + + while (((res = read(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) && + (EINTR == errno)) + ; + if (res < 0) { + perror("reading (rd) on sg device, error"); + return -1; + } + switch (sg_err_category3(&io_hdr)) { + case SG_ERR_CAT_CLEAN: + break; + case SG_ERR_CAT_RECOVERED: + fprintf(stderr, "Recovered error while reading block=%d, num=%d\n", + from_block, blocks); + break; + case SG_ERR_CAT_MEDIA_CHANGED: + return 2; + default: + sg_chk_n_print3("reading", &io_hdr); + return -1; + } + if (diop && *diop && + ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) + *diop = 0; /* flag that dio not done (completely) */ + sum_of_resids += io_hdr.resid; +#if SG_DEBUG + fprintf(stderr, "duration=%u ms\n", io_hdr.duration); +#endif + return 0; +} + +/* -1 -> unrecoverable error, 0 -> successful, 1 -> recoverable (ENOMEM), + 2 -> try again */ +int sg_write(int sg_fd, unsigned char * buff, unsigned int blocks, unsigned int to_block, + int bs, int * diop) +{ + unsigned char wrCmd[10] = {0x2a, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + unsigned char senseBuff[SENSE_BUFF_LEN]; + sg_io_hdr_t io_hdr; + int res; + + wrCmd[2] = (unsigned char)((to_block >> 24) & 0xFF); + wrCmd[3] = (unsigned char)((to_block >> 16) & 0xFF); + wrCmd[4] = (unsigned char)((to_block >> 8) & 0xFF); + wrCmd[5] = (unsigned char)(to_block & 0xFF); + wrCmd[7] = (unsigned char)((blocks >> 8) & 0xff); + wrCmd[8] = (unsigned char)(blocks & 0xff); + + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof(wrCmd); + io_hdr.cmdp = wrCmd; + io_hdr.dxfer_direction = SG_DXFER_TO_DEV; + io_hdr.dxfer_len = bs * blocks; + io_hdr.dxferp = buff; + io_hdr.mx_sb_len = SENSE_BUFF_LEN; + io_hdr.sbp = senseBuff; + io_hdr.timeout = DEF_TIMEOUT; + io_hdr.pack_id = to_block; + if (diop && *diop) + io_hdr.flags |= SG_FLAG_DIRECT_IO; + + while (((res = write(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) && + (EINTR == errno)) + ; + if (res < 0) { + if (ENOMEM == errno) + return 1; + perror("writing (wr) on sg device, error"); + return -1; + } + + while (((res = read(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) && + (EINTR == errno)) + ; + if (res < 0) { + perror("writing (rd) on sg device, error"); + return -1; + } + switch (sg_err_category3(&io_hdr)) { + case SG_ERR_CAT_CLEAN: + break; + case SG_ERR_CAT_RECOVERED: + fprintf(stderr, "Recovered error while writing block=%d, num=%d\n", + to_block, blocks); + break; + case SG_ERR_CAT_MEDIA_CHANGED: + return 2; + default: + sg_chk_n_print3("writing", &io_hdr); + return -1; + } + if (diop && *diop && + ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) + *diop = 0; /* flag that dio not done (completely) */ + return 0; +} + +static int get_num(char * buf) +{ + int res, num; + char c; + + res = sscanf(buf, "%d%c", &num, &c); + if (0 == res) + return -1; + else if (1 == res) + return num; + else { + switch (c) { + case 'c': + case 'C': + return num; + case 'b': + case 'B': + return num * 512; + case 'k': + return num * 1024; + case 'K': + return num * 1000; + case 'm': + return num * 1024 * 1024; + case 'M': + return num * 1000000; + case 'g': + return num * 1024 * 1024 * 1024; + case 'G': + return num * 1000000000; + default: + fprintf(stderr, "unrecognized multiplier\n"); + return -1; + } + } +} + +#if 0 +static int sg_dd_main(int argc, char * argv[]) +{ + int skip = 0; + int seek = 0; + int bs = 0; + int ibs = 0; + int obs = 0; + int bpt = DEF_BLOCKS_PER_TRANSFER; + char str[512]; + char * key; + char * buf; + char inf[512]; + int in_type = FT_OTHER; + char outf[512]; + int out_type = FT_OTHER; + int dio = 0; + int dio_incomplete = 0; + int res, k, t, buf_sz, dio_tmp; + int infd, outfd, blocks; + unsigned char * wrkBuff; + unsigned char * wrkPos; + int in_num_sect = 0; + int out_num_sect = 0; + int in_sect_sz, out_sect_sz; + char ebuff[256]; + int blocks_per; + + inf[0] = '\0'; + outf[0] = '\0'; + if (argc < 2) { + usage(); + return 1; + } + + for(k = 1; k < argc; k++) { + if (argv[k]) + strcpy(str, argv[k]); + else + continue; + for(key = str, buf = key; *buf && *buf != '=';) + buf++; + if (*buf) + *buf++ = '\0'; + if (strcmp(key,"if") == 0) + strcpy(inf, buf); + else if (strcmp(key,"of") == 0) + strcpy(outf, buf); + else if (0 == strcmp(key,"ibs")) + ibs = get_num(buf); + else if (0 == strcmp(key,"obs")) + obs = get_num(buf); + else if (0 == strcmp(key,"bs")) + bs = get_num(buf); + else if (0 == strcmp(key,"bpt")) + bpt = get_num(buf); + else if (0 == strcmp(key,"skip")) + skip = get_num(buf); + else if (0 == strcmp(key,"seek")) + seek = get_num(buf); + else if (0 == strcmp(key,"count")) + dd_count = get_num(buf); + else if (0 == strcmp(key,"dio")) + dio = get_num(buf); + else { + fprintf(stderr, "Unrecognized argument '%s'\n", key); + usage(); + return 1; + } + } + if (bs <= 0) { + bs = DEF_BLOCK_SIZE; + fprintf(stderr, "Assume default 'bs' (block size) of %d bytes\n", bs); + } + if ((ibs && (ibs != bs)) || (obs && (obs != bs))) { + fprintf(stderr, "If 'ibs' or 'obs' given must be same as 'bs'\n"); + usage(); + return 1; + } + if ((skip < 0) || (seek < 0)) { + fprintf(stderr, "skip and seek cannot be negative\n"); + return 1; + } +#ifdef SG_DEBUG + fprintf(stderr, "sg_dd: if=%s skip=%d of=%s seek=%d count=%d\n", + inf, skip, outf, seek, dd_count); +#endif + install_handler (SIGINT, interrupt_handler); + install_handler (SIGQUIT, interrupt_handler); + install_handler (SIGPIPE, interrupt_handler); + install_handler (SIGUSR1, siginfo_handler); + + infd = STDIN_FILENO; + outfd = STDOUT_FILENO; + if (inf[0] && ('-' != inf[0])) { + in_type = dd_filetype(inf); + + if (FT_SG == in_type) { + if ((infd = open(inf, O_RDWR)) < 0) { + sprintf(ebuff, "sg_dd: could not open %s for sg reading", inf); + perror(ebuff); + return 1; + } + t = bs * bpt; + res = ioctl(infd, SG_SET_RESERVED_SIZE, &t); + if (res < 0) + perror("sg_dd: SG_SET_RESERVED_SIZE error"); + res = ioctl(infd, SG_GET_VERSION_NUM, &t); + if ((res < 0) || (t < 30000)) { + fprintf(stderr, "sg_dd: sg driver prior to 3.x.y\n"); + return 1; + } + } + if (FT_SG != in_type) { + if ((infd = open(inf, O_RDONLY)) < 0) { + sprintf(ebuff, "sg_dd: could not open %s for reading", inf); + perror(ebuff); + return 1; + } + else if (skip > 0) { + llse_loff_t offset = skip; + + offset *= bs; /* could exceed 32 bits here! */ + if (llse_llseek(infd, offset, SEEK_SET) < 0) { + sprintf(ebuff, + "sg_dd: couldn't skip to required position on %s", inf); + perror(ebuff); + return 1; + } + } + } + } + + if (outf[0] && ('-' != outf[0])) { + out_type = dd_filetype(outf); + + if (FT_SG == out_type) { + if ((outfd = open(outf, O_RDWR)) < 0) { + sprintf(ebuff, "sg_dd: could not open %s for sg writing", outf); + perror(ebuff); + return 1; + } + t = bs * bpt; + res = ioctl(outfd, SG_SET_RESERVED_SIZE, &t); + if (res < 0) + perror("sg_dd: SG_SET_RESERVED_SIZE error"); + res = ioctl(outfd, SG_GET_VERSION_NUM, &t); + if ((res < 0) || (t < 30000)) { + fprintf(stderr, "sg_dd: sg driver prior to 3.x.y\n"); + return 1; + } + } + else { + if (FT_OTHER == out_type) { + if ((outfd = open(outf, O_WRONLY | O_CREAT, 0666)) < 0) { + sprintf(ebuff, + "sg_dd: could not open %s for writing", outf); + perror(ebuff); + return 1; + } + } + else { + if ((outfd = open(outf, O_WRONLY)) < 0) { + sprintf(ebuff, + "sg_dd: could not open %s for raw writing", outf); + perror(ebuff); + return 1; + } + } + if (seek > 0) { + llse_loff_t offset = seek; + + offset *= bs; /* could exceed 32 bits here! */ + if (llse_llseek(outfd, offset, SEEK_SET) < 0) { + sprintf(ebuff, + "sg_dd: couldn't seek to required position on %s", outf); + perror(ebuff); + return 1; + } + } + } + } + if ((STDIN_FILENO == infd) && (STDOUT_FILENO == outfd)) { + fprintf(stderr, + "Can't have both 'if' as stdin _and_ 'of' as stdout\n"); + return 1; + } +#if 1 + if ((FT_OTHER == in_type) && (FT_OTHER == out_type)) { + fprintf(stderr, "Both 'if' and 'of' can't be ordinary files\n"); + return 1; + } +#endif + if (0 == dd_count) + return 0; + else if (dd_count < 0) { + if (FT_SG == in_type) { + res = read_capacity(infd, &in_num_sect, &in_sect_sz); + if (2 == res) { + fprintf(stderr, + "Unit attention, media changed(in), try again\n"); + res = read_capacity(infd, &in_num_sect, &in_sect_sz); + } + if (0 != res) { + fprintf(stderr, "Unable to read capacity on %s\n", inf); + in_num_sect = -1; + } + else { +#if 0 + if (0 == in_sect_sz) + in_sect_sz = bs; + else if (in_sect_sz > bs) + in_num_sect *= (in_sect_sz / bs); + else if (in_sect_sz < bs) + in_num_sect /= (bs / in_sect_sz); +#endif + if (in_num_sect > skip) + in_num_sect -= skip; + } + } + if (FT_SG == out_type) { + res = read_capacity(outfd, &out_num_sect, &out_sect_sz); + if (2 == res) { + fprintf(stderr, + "Unit attention, media changed(out), try again\n"); + res = read_capacity(outfd, &out_num_sect, &out_sect_sz); + } + if (0 != res) { + fprintf(stderr, "Unable to read capacity on %s\n", outf); + out_num_sect = -1; + } + else { + if (out_num_sect > seek) + out_num_sect -= seek; + } + } +#ifdef SG_DEBUG + fprintf(stderr, + "Start of loop, count=%d, in_num_sect=%d, out_num_sect=%d\n", + dd_count, in_num_sect, out_num_sect); +#endif + if (in_num_sect > 0) { + if (out_num_sect > 0) + dd_count = (in_num_sect > out_num_sect) ? out_num_sect : + in_num_sect; + else + dd_count = in_num_sect; + } + else + dd_count = out_num_sect; + } + if (dd_count <= 0) { + fprintf(stderr, "Couldn't calculate count, please give one\n"); + return 1; + } + + if (dio || (FT_RAW == in_type) || (FT_RAW == out_type)) { + size_t psz = getpagesize(); + wrkBuff = malloc(bs * bpt + psz); + if (0 == wrkBuff) { + fprintf(stderr, "Not enough user memory for raw\n"); + return 1; + } + wrkPos = (unsigned char *)(((unsigned long)wrkBuff + psz - 1) & + (~(psz - 1))); + } + else { + wrkBuff = malloc(bs * bpt); + if (0 == wrkBuff) { + fprintf(stderr, "Not enough user memory\n"); + return 1; + } + wrkPos = wrkBuff; + } + + blocks_per = bpt; +#ifdef SG_DEBUG + fprintf(stderr, "Start of loop, count=%d, blocks_per=%d\n", + dd_count, blocks_per); +#endif + while (dd_count > 0) { + blocks = (dd_count > blocks_per) ? blocks_per : dd_count; + if (FT_SG == in_type) { + dio_tmp = dio; + res = sg_read(infd, wrkPos, blocks, skip, bs, &dio_tmp); + if (1 == res) { /* ENOMEM, find what's available+try that */ + if (ioctl(infd, SG_GET_RESERVED_SIZE, &buf_sz) < 0) { + perror("RESERVED_SIZE ioctls failed"); + break; + } + blocks_per = (buf_sz + bs - 1) / bs; + blocks = blocks_per; + fprintf(stderr, + "Reducing read to %d blocks per loop\n", blocks_per); + res = sg_read(infd, wrkPos, blocks, skip, bs, &dio_tmp); + } + else if (2 == res) { + fprintf(stderr, + "Unit attention, media changed, try again (r)\n"); + res = sg_read(infd, wrkPos, blocks, skip, bs, &dio_tmp); + } + if (0 != res) { + fprintf(stderr, "sg_read failed, skip=%d\n", skip); + break; + } + else { + in_full += blocks; + if (dio && (0 == dio_tmp)) + dio_incomplete++; + } + } + else { + while (((res = read(infd, wrkPos, blocks * bs)) < 0) && + (EINTR == errno)) + ; + if (res < 0) { + sprintf(ebuff, "sg_dd: reading, skip=%d ", skip); + perror(ebuff); + break; + } + else if (res < blocks * bs) { + dd_count = 0; + blocks = res / bs; + if ((res % bs) > 0) { + blocks++; + in_partial++; + } + } + in_full += blocks; + } + + if (FT_SG == out_type) { + dio_tmp = dio; + res = sg_write(outfd, wrkPos, blocks, seek, bs, &dio_tmp); + if (1 == res) { /* ENOMEM, find what's available+try that */ + if (ioctl(outfd, SG_GET_RESERVED_SIZE, &buf_sz) < 0) { + perror("RESERVED_SIZE ioctls failed"); + break; + } + blocks_per = (buf_sz + bs - 1) / bs; + blocks = blocks_per; + fprintf(stderr, + "Reducing write to %d blocks per loop\n", blocks); + res = sg_write(outfd, wrkPos, blocks, seek, bs, &dio_tmp); + } + else if (2 == res) { + fprintf(stderr, + "Unit attention, media changed, try again (w)\n"); + res = sg_write(outfd, wrkPos, blocks, seek, bs, &dio_tmp); + } + else if (0 != res) { + fprintf(stderr, "sg_write failed, seek=%d\n", seek); + break; + } + else { + out_full += blocks; + if (dio && (0 == dio_tmp)) + dio_incomplete++; + } + } + else { + while (((res = write(outfd, wrkPos, blocks * bs)) < 0) + && (EINTR == errno)) + ; + if (res < 0) { + sprintf(ebuff, "sg_dd: writing, seek=%d ", seek); + perror(ebuff); + break; + } + else if (res < blocks * bs) { + fprintf(stderr, "output file probably full, seek=%d ", seek); + blocks = res / bs; + out_full += blocks; + if ((res % bs) > 0) + out_partial++; + break; + } + else + out_full += blocks; + } + if (dd_count > 0) + dd_count -= blocks; + skip += blocks; + seek += blocks; + } + + free(wrkBuff); + if (STDIN_FILENO != infd) + close(infd); + if (STDOUT_FILENO != outfd) + close(outfd); + res = 0; + if (0 != dd_count) { + fprintf(stderr, "Some error occurred,"); + res = 2; + } + print_stats(); + if (dio_incomplete) + fprintf(stderr, ">> Direct IO requested but incomplete %d times\n", + dio_incomplete); + if (sum_of_resids) + fprintf(stderr, ">> Non-zero sum of residual counts=%d\n", + sum_of_resids); + return res; +} +#endif diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/sg_dd.h parted-1.4.7-gpt/libparted/sg_dd.h --- parted-1.4.7/libparted/sg_dd.h Wed Dec 31 18:00:00 1969 +++ parted-1.4.7-gpt/libparted/sg_dd.h Thu Jan 18 11:24:42 2001 @@ -0,0 +1,23 @@ + /* + libparted - a library for manipulating disk partitions + Copyright (C) 1998-2000 Free Software Foundation, Inc. + + 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 +*/ + +int sg_write(int sg_fd, unsigned char * buff, unsigned int blocks, unsigned int to_block, + int bs, int * diop); +int sg_read(int sg_fd, unsigned char * buff, unsigned int blocks, unsigned int from_block, + int bs, int * diop); diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/sg_err.c parted-1.4.7-gpt/libparted/sg_err.c --- parted-1.4.7/libparted/sg_err.c Wed Dec 31 18:00:00 1969 +++ parted-1.4.7-gpt/libparted/sg_err.c Thu Jan 18 11:24:42 2001 @@ -0,0 +1,648 @@ + /* + libparted - a library for manipulating disk partitions + Copyright (C) 1998-2000 Free Software Foundation, Inc. + +*/ +#include +#include +#include "sg_err.h" + +/* This file is a huge cut, paste and hack from linux/drivers/scsi/constant.c +* which I guess was written by: +* Copyright (C) 1993, 1994, 1995 Eric Youngdale + +* The rest of this is: +* Copyright (C) 1999 D. Gilbert +* +* 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, or (at your option) +* any later version. +* +* ASCII values for a number of symbolic constants, printing functions, etc. +* +* Some of the tables have been updated for SCSI 2. +* +* Version 0.83 (991208) +*/ + + +static const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, + 12, 12, 10, 10 }; + +#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7] + +static const char unknown[] = "UNKNOWN"; + +static const char * group_0_commands[] = { +/* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense", +/* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks", +/* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown, +/* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry", +/* 13-16 */ "Verify", "Recover Buffered Data", "Mode Select", "Reserve", +/* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit", +/* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", +/* 1e-1f */ "Prevent/Allow Medium Removal", unknown, +}; + + +static const char *group_1_commands[] = { +/* 20-22 */ unknown, unknown, unknown, +/* 23-28 */ unknown, "Define window parameters", "Read Capacity", + unknown, unknown, "Read (10)", +/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase", + "Read updated block", +/* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", +/* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", +/* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data", +/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer", + "Read Buffer", +/* 3d-3f */ "Update Block", "Read Long", "Write Long", +}; + +static const char *group_2_commands[] = { +/* 40-41 */ "Change Definition", "Write Same", +/* 42-48 */ "Read sub-channel", "Read TOC", "Read header", + "Play audio (10)", unknown, "Play audio msf", + "Play audio track/index", +/* 49-4f */ "Play track relative (10)", unknown, "Pause/resume", + "Log Select", "Log Sense", unknown, unknown, +/* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)", +/* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown, +/* 5c-5f */ unknown, unknown, unknown, +}; + + +/* The following are 12 byte commands in group 5 */ +static const char *group_5_commands[] = { +/* a0-a5 */ unknown, unknown, unknown, unknown, unknown, + "Move medium/play audio(12)", +/* a6-a9 */ "Exchange medium", unknown, "Read(12)", "Play track relative(12)", +/* aa-ae */ "Write(12)", unknown, "Erase(12)", unknown, + "Write and verify(12)", +/* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)", +/* b2-b4 */ "Search data low(12)", "Set limits(12)", unknown, +/* b5-b6 */ "Request volume element address", "Send volume tag", +/* b7-b9 */ "Read defect data(12)", "Read element status", unknown, +/* ba-bf */ unknown, unknown, unknown, unknown, unknown, unknown, +}; + + + + +#define group(opcode) (((opcode) >> 5) & 7) + +#define RESERVED_GROUP 0 +#define VENDOR_GROUP 1 + +static const char **commands[] = { + group_0_commands, group_1_commands, group_2_commands, + (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, + group_5_commands, (const char **) VENDOR_GROUP, + (const char **) VENDOR_GROUP +}; + +static const char reserved[] = "RESERVED"; +static const char vendor[] = "VENDOR SPECIFIC"; + +static void print_opcode(int opcode) { + const char **table = commands[ group(opcode) ]; + switch ((unsigned long) table) { + case RESERVED_GROUP: + printf("%s(0x%02x) ", reserved, opcode); + break; + case VENDOR_GROUP: + printf("%s(0x%02x) ", vendor, opcode); + break; + default: + if (table[opcode & 0x1f] != unknown) + printf("%s ",table[opcode & 0x1f]); + else + printf("%s(0x%02x) ", unknown, opcode); + break; + } +} + +void sg_print_command (const unsigned char * command) { + int i,s; + print_opcode(command[0]); + for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) + printf("%02x ", command[i]); + printf("\n"); +} + +static const char * statuses[] = { +/* 0-4 */ "Good", "Check Condition", "Condition Met", unknown, "Busy", +/* 5-9 */ unknown, unknown, unknown, "Intermediate", unknown, +/* a-c */ "Intermediate-Condition Met", unknown, "Reservation Conflict", +/* d-10 */ unknown, unknown, unknown, unknown, +/* 11-14 */ "Command Terminated", unknown, unknown, "Queue Full", +/* 15-1a */ unknown, unknown, unknown, unknown, unknown, unknown, +/* 1b-1f */ unknown, unknown, unknown, unknown, unknown, +}; + +void sg_print_status (int masked_status) { + /* status = (status >> 1) & 0xf; */ /* already done */ + printf("%s ",statuses[masked_status]); +} + +#define D 0x001 /* DIRECT ACCESS DEVICE (disk) */ +#define T 0x002 /* SEQUENTIAL ACCESS DEVICE (tape) */ +#define L 0x004 /* PRINTER DEVICE */ +#define P 0x008 /* PROCESSOR DEVICE */ +#define W 0x010 /* WRITE ONCE READ MULTIPLE DEVICE */ +#define R 0x020 /* READ ONLY (CD-ROM) DEVICE */ +#define S 0x040 /* SCANNER DEVICE */ +#define O 0x080 /* OPTICAL MEMORY DEVICE */ +#define M 0x100 /* MEDIA CHANGER DEVICE */ +#define C 0x200 /* COMMUNICATION DEVICE */ + +struct error_info{ + unsigned char code1, code2; + unsigned short int devices; + const char * text; +}; + +struct error_info2{ + unsigned char code1, code2_min, code2_max; + unsigned short int devices; + const char * text; +}; + +static struct error_info2 additional2[] = +{ + {0x40,0x00,0x7f,D,"Ram failure (%x)"}, + {0x40,0x80,0xff,D|T|L|P|W|R|S|O|M|C,"Diagnostic failure on component (%x)"}, + {0x41,0x00,0xff,D,"Data path failure (%x)"}, + {0x42,0x00,0xff,D,"Power-on or self-test failure (%x)"}, + {0, 0, 0, 0, NULL} +}; + +static struct error_info additional[] = +{ + {0x00,0x01,T,"Filemark detected"}, + {0x00,0x02,T|S,"End-of-partition/medium detected"}, + {0x00,0x03,T,"Setmark detected"}, + {0x00,0x04,T|S,"Beginning-of-partition/medium detected"}, + {0x00,0x05,T|S,"End-of-data detected"}, + {0x00,0x06,D|T|L|P|W|R|S|O|M|C,"I/O process terminated"}, + {0x00,0x11,R,"Audio play operation in progress"}, + {0x00,0x12,R,"Audio play operation paused"}, + {0x00,0x13,R,"Audio play operation successfully completed"}, + {0x00,0x14,R,"Audio play operation stopped due to error"}, + {0x00,0x15,R,"No current audio status to return"}, + {0x01,0x00,D|W|O,"No index/sector signal"}, + {0x02,0x00,D|W|R|O|M,"No seek complete"}, + {0x03,0x00,D|T|L|W|S|O,"Peripheral device write fault"}, + {0x03,0x01,T,"No write current"}, + {0x03,0x02,T,"Excessive write errors"}, + {0x04,0x00,D|T|L|P|W|R|S|O|M|C, + "Logical unit not ready, cause not reportable"}, + {0x04,0x01,D|T|L|P|W|R|S|O|M|C, + "Logical unit is in process of becoming ready"}, + {0x04,0x02,D|T|L|P|W|R|S|O|M|C, + "Logical unit not ready, initializing command required"}, + {0x04,0x03,D|T|L|P|W|R|S|O|M|C, + "Logical unit not ready, manual intervention required"}, + {0x04,0x04,D|T|L|O,"Logical unit not ready, format in progress"}, + {0x05,0x00,D|T|L|W|R|S|O|M|C,"Logical unit does not respond to selection"}, + {0x06,0x00,D|W|R|O|M,"No reference position found"}, + {0x07,0x00,D|T|L|W|R|S|O|M,"Multiple peripheral devices selected"}, + {0x08,0x00,D|T|L|W|R|S|O|M|C,"Logical unit communication failure"}, + {0x08,0x01,D|T|L|W|R|S|O|M|C,"Logical unit communication time-out"}, + {0x08,0x02,D|T|L|W|R|S|O|M|C,"Logical unit communication parity error"}, + {0x09,0x00,D|T|W|R|O,"Track following error"}, + {0x09,0x01,W|R|O,"Tracking servo failure"}, + {0x09,0x02,W|R|O,"Focus servo failure"}, + {0x09,0x03,W|R|O,"Spindle servo failure"}, + {0x0A,0x00,D|T|L|P|W|R|S|O|M|C,"Error log overflow"}, + {0x0C,0x00,T|S,"Write error"}, + {0x0C,0x01,D|W|O,"Write error recovered with auto reallocation"}, + {0x0C,0x02,D|W|O,"Write error - auto reallocation failed"}, + {0x10,0x00,D|W|O,"Id crc or ecc error"}, + {0x11,0x00,D|T|W|R|S|O,"Unrecovered read error"}, + {0x11,0x01,D|T|W|S|O,"Read retries exhausted"}, + {0x11,0x02,D|T|W|S|O,"Error too long to correct"}, + {0x11,0x03,D|T|W|S|O,"Multiple read errors"}, + {0x11,0x04,D|W|O,"Unrecovered read error - auto reallocate failed"}, + {0x11,0x05,W|R|O,"L-ec uncorrectable error"}, + {0x11,0x06,W|R|O,"Circ unrecovered error"}, + {0x11,0x07,W|O,"Data resynchronization error"}, + {0x11,0x08,T,"Incomplete block read"}, + {0x11,0x09,T,"No gap found"}, + {0x11,0x0A,D|T|O,"Miscorrected error"}, + {0x11,0x0B,D|W|O,"Unrecovered read error - recommend reassignment"}, + {0x11,0x0C,D|W|O,"Unrecovered read error - recommend rewrite the data"}, + {0x12,0x00,D|W|O,"Address mark not found for id field"}, + {0x13,0x00,D|W|O,"Address mark not found for data field"}, + {0x14,0x00,D|T|L|W|R|S|O,"Recorded entity not found"}, + {0x14,0x01,D|T|W|R|O,"Record not found"}, + {0x14,0x02,T,"Filemark or setmark not found"}, + {0x14,0x03,T,"End-of-data not found"}, + {0x14,0x04,T,"Block sequence error"}, + {0x15,0x00,D|T|L|W|R|S|O|M,"Random positioning error"}, + {0x15,0x01,D|T|L|W|R|S|O|M,"Mechanical positioning error"}, + {0x15,0x02,D|T|W|R|O,"Positioning error detected by read of medium"}, + {0x16,0x00,D|W|O,"Data synchronization mark error"}, + {0x17,0x00,D|T|W|R|S|O,"Recovered data with no error correction applied"}, + {0x17,0x01,D|T|W|R|S|O,"Recovered data with retries"}, + {0x17,0x02,D|T|W|R|O,"Recovered data with positive head offset"}, + {0x17,0x03,D|T|W|R|O,"Recovered data with negative head offset"}, + {0x17,0x04,W|R|O,"Recovered data with retries and/or circ applied"}, + {0x17,0x05,D|W|R|O,"Recovered data using previous sector id"}, + {0x17,0x06,D|W|O,"Recovered data without ecc - data auto-reallocated"}, + {0x17,0x07,D|W|O,"Recovered data without ecc - recommend reassignment"}, + {0x18,0x00,D|T|W|R|O,"Recovered data with error correction applied"}, + {0x18,0x01,D|W|R|O,"Recovered data with error correction and retries applied"}, + {0x18,0x02,D|W|R|O,"Recovered data - data auto-reallocated"}, + {0x18,0x03,R,"Recovered data with circ"}, + {0x18,0x04,R,"Recovered data with lec"}, + {0x18,0x05,D|W|R|O,"Recovered data - recommend reassignment"}, + {0x19,0x00,D|O,"Defect list error"}, + {0x19,0x01,D|O,"Defect list not available"}, + {0x19,0x02,D|O,"Defect list error in primary list"}, + {0x19,0x03,D|O,"Defect list error in grown list"}, + {0x1A,0x00,D|T|L|P|W|R|S|O|M|C,"Parameter list length error"}, + {0x1B,0x00,D|T|L|P|W|R|S|O|M|C,"Synchronous data transfer error"}, + {0x1C,0x00,D|O,"Defect list not found"}, + {0x1C,0x01,D|O,"Primary defect list not found"}, + {0x1C,0x02,D|O,"Grown defect list not found"}, + {0x1D,0x00,D|W|O,"Miscompare during verify operation"}, + {0x1E,0x00,D|W|O,"Recovered id with ecc correction"}, + {0x20,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid command operation code"}, + {0x21,0x00,D|T|W|R|O|M,"Logical block address out of range"}, + {0x21,0x01,M,"Invalid element address"}, + {0x22,0x00,D,"Illegal function (should use 20 00, 24 00, or 26 00)"}, + {0x24,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid field in cdb"}, + {0x25,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit not supported"}, + {0x26,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid field in parameter list"}, + {0x26,0x01,D|T|L|P|W|R|S|O|M|C,"Parameter not supported"}, + {0x26,0x02,D|T|L|P|W|R|S|O|M|C,"Parameter value invalid"}, + {0x26,0x03,D|T|L|P|W|R|S|O|M|C,"Threshold parameters not supported"}, + {0x27,0x00,D|T|W|O,"Write protected"}, + {0x28,0x00,D|T|L|P|W|R|S|O|M|C,"Not ready to ready transition (medium may have changed)"}, + {0x28,0x01,M,"Import or export element accessed"}, + {0x29,0x00,D|T|L|P|W|R|S|O|M|C,"Power on, reset, or bus device reset occurred"}, + {0x2A,0x00,D|T|L|W|R|S|O|M|C,"Parameters changed"}, + {0x2A,0x01,D|T|L|W|R|S|O|M|C,"Mode parameters changed"}, + {0x2A,0x02,D|T|L|W|R|S|O|M|C,"Log parameters changed"}, + {0x2B,0x00,D|T|L|P|W|R|S|O|C,"Copy cannot execute since host cannot disconnect"}, + {0x2C,0x00,D|T|L|P|W|R|S|O|M|C,"Command sequence error"}, + {0x2C,0x01,S,"Too many windows specified"}, + {0x2C,0x02,S,"Invalid combination of windows specified"}, + {0x2D,0x00,T,"Overwrite error on update in place"}, + {0x2F,0x00,D|T|L|P|W|R|S|O|M|C,"Commands cleared by another initiator"}, + {0x30,0x00,D|T|W|R|O|M,"Incompatible medium installed"}, + {0x30,0x01,D|T|W|R|O,"Cannot read medium - unknown format"}, + {0x30,0x02,D|T|W|R|O,"Cannot read medium - incompatible format"}, + {0x30,0x03,D|T,"Cleaning cartridge installed"}, + {0x31,0x00,D|T|W|O,"Medium format corrupted"}, + {0x31,0x01,D|L|O,"Format command failed"}, + {0x32,0x00,D|W|O,"No defect spare location available"}, + {0x32,0x01,D|W|O,"Defect list update failure"}, + {0x33,0x00,T,"Tape length error"}, + {0x36,0x00,L,"Ribbon, ink, or toner failure"}, + {0x37,0x00,D|T|L|W|R|S|O|M|C,"Rounded parameter"}, + {0x39,0x00,D|T|L|W|R|S|O|M|C,"Saving parameters not supported"}, + {0x3A,0x00,D|T|L|W|R|S|O|M,"Medium not present"}, + {0x3B,0x00,T|L,"Sequential positioning error"}, + {0x3B,0x01,T,"Tape position error at beginning-of-medium"}, + {0x3B,0x02,T,"Tape position error at end-of-medium"}, + {0x3B,0x03,L,"Tape or electronic vertical forms unit not ready"}, + {0x3B,0x04,L,"Slew failure"}, + {0x3B,0x05,L,"Paper jam"}, + {0x3B,0x06,L,"Failed to sense top-of-form"}, + {0x3B,0x07,L,"Failed to sense bottom-of-form"}, + {0x3B,0x08,T,"Reposition error"}, + {0x3B,0x09,S,"Read past end of medium"}, + {0x3B,0x0A,S,"Read past beginning of medium"}, + {0x3B,0x0B,S,"Position past end of medium"}, + {0x3B,0x0C,S,"Position past beginning of medium"}, + {0x3B,0x0D,M,"Medium destination element full"}, + {0x3B,0x0E,M,"Medium source element empty"}, + {0x3D,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid bits in identify message"}, + {0x3E,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit has not self-configured yet"}, + {0x3F,0x00,D|T|L|P|W|R|S|O|M|C,"Target operating conditions have changed"}, + {0x3F,0x01,D|T|L|P|W|R|S|O|M|C,"Microcode has been changed"}, + {0x3F,0x02,D|T|L|P|W|R|S|O|M|C,"Changed operating definition"}, + {0x3F,0x03,D|T|L|P|W|R|S|O|M|C,"Inquiry data has changed"}, + {0x43,0x00,D|T|L|P|W|R|S|O|M|C,"Message error"}, + {0x44,0x00,D|T|L|P|W|R|S|O|M|C,"Internal target failure"}, + {0x45,0x00,D|T|L|P|W|R|S|O|M|C,"Select or reselect failure"}, + {0x46,0x00,D|T|L|P|W|R|S|O|M|C,"Unsuccessful soft reset"}, + {0x47,0x00,D|T|L|P|W|R|S|O|M|C,"Scsi parity error"}, + {0x48,0x00,D|T|L|P|W|R|S|O|M|C,"Initiator detected error message received"}, + {0x49,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid message error"}, + {0x4A,0x00,D|T|L|P|W|R|S|O|M|C,"Command phase error"}, + {0x4B,0x00,D|T|L|P|W|R|S|O|M|C,"Data phase error"}, + {0x4C,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit failed self-configuration"}, + {0x4E,0x00,D|T|L|P|W|R|S|O|M|C,"Overlapped commands attempted"}, + {0x50,0x00,T,"Write append error"}, + {0x50,0x01,T,"Write append position error"}, + {0x50,0x02,T,"Position error related to timing"}, + {0x51,0x00,T|O,"Erase failure"}, + {0x52,0x00,T,"Cartridge fault"}, + {0x53,0x00,D|T|L|W|R|S|O|M,"Media load or eject failed"}, + {0x53,0x01,T,"Unload tape failure"}, + {0x53,0x02,D|T|W|R|O|M,"Medium removal prevented"}, + {0x54,0x00,P,"Scsi to host system interface failure"}, + {0x55,0x00,P,"System resource failure"}, + {0x57,0x00,R,"Unable to recover table-of-contents"}, + {0x58,0x00,O,"Generation does not exist"}, + {0x59,0x00,O,"Updated block read"}, + {0x5A,0x00,D|T|L|P|W|R|S|O|M,"Operator request or state change input (unspecified)"}, + {0x5A,0x01,D|T|W|R|O|M,"Operator medium removal request"}, + {0x5A,0x02,D|T|W|O,"Operator selected write protect"}, + {0x5A,0x03,D|T|W|O,"Operator selected write permit"}, + {0x5B,0x00,D|T|L|P|W|R|S|O|M,"Log exception"}, + {0x5B,0x01,D|T|L|P|W|R|S|O|M,"Threshold condition met"}, + {0x5B,0x02,D|T|L|P|W|R|S|O|M,"Log counter at maximum"}, + {0x5B,0x03,D|T|L|P|W|R|S|O|M,"Log list codes exhausted"}, + {0x5C,0x00,D|O,"Rpl status change"}, + {0x5C,0x01,D|O,"Spindles synchronized"}, + {0x5C,0x02,D|O,"Spindles not synchronized"}, + {0x60,0x00,S,"Lamp failure"}, + {0x61,0x00,S,"Video acquisition error"}, + {0x61,0x01,S,"Unable to acquire video"}, + {0x61,0x02,S,"Out of focus"}, + {0x62,0x00,S,"Scan head positioning error"}, + {0x63,0x00,R,"End of user area encountered on this track"}, + {0x64,0x00,R,"Illegal mode for this track"}, + {0, 0, 0, NULL} +}; + +static const char *snstext[] = { + "None", /* There is no sense information */ + "Recovered Error", /* The last command completed successfully + but used error correction */ + "Not Ready", /* The addressed target is not ready */ + "Medium Error", /* Data error detected on the medium */ + "Hardware Error", /* Controller or device failure */ + "Illegal Request", + "Unit Attention", /* Removable medium was changed, or + the target has been reset */ + "Data Protect", /* Access to the data is blocked */ + "Blank Check", /* Reached unexpected written or unwritten + region of the medium */ + "Key=9", /* Vendor specific */ + "Copy Aborted", /* COPY or COMPARE was aborted */ + "Aborted Command", /* The target aborted the command */ + "Equal", /* A SEARCH DATA command found data equal */ + "Volume Overflow", /* Medium full with still data to be written */ + "Miscompare", /* Source data and data on the medium + do not agree */ + "Key=15" /* Reserved */ +}; + +/* Print sense information */ +void sg_print_sense(const char * leadin, const unsigned char * sense_buffer, + int sb_len) +{ + int i, s; + int sense_class, valid, code; + const char * error = NULL; + + sense_class = (sense_buffer[0] >> 4) & 0x07; + code = sense_buffer[0] & 0xf; + valid = sense_buffer[0] & 0x80; + + if (sense_class == 7) { /* extended sense data */ + s = sense_buffer[7] + 8; + if(s > sb_len) + s = sb_len; + + if (!valid) + printf("[valid=0] "); + printf("Info fld=0x%x, ", (int)((sense_buffer[3] << 24) | + (sense_buffer[4] << 16) | (sense_buffer[5] << 8) | + sense_buffer[6])); + + if (sense_buffer[2] & 0x80) + printf( "FMK "); /* current command has read a filemark */ + if (sense_buffer[2] & 0x40) + printf( "EOM "); /* end-of-medium condition exists */ + if (sense_buffer[2] & 0x20) + printf( "ILI "); /* incorrect block length requested */ + + switch (code) { + case 0x0: + error = "Current"; /* error concerns current command */ + break; + case 0x1: + error = "Deferred"; /* error concerns some earlier command */ + /* e.g., an earlier write to disk cache succeeded, but + now the disk discovers that it cannot write the data */ + break; + default: + error = "Invalid"; + } + + printf("%s ", error); + + if (leadin) + printf("%s: ", leadin); + printf("sense key: %s\n", snstext[sense_buffer[2] & 0x0f]); + + /* Check to see if additional sense information is available */ + if(sense_buffer[7] + 7 < 13 || + (sense_buffer[12] == 0 && sense_buffer[13] == 0)) goto done; + + for(i=0; additional[i].text; i++) + if(additional[i].code1 == sense_buffer[12] && + additional[i].code2 == sense_buffer[13]) + printf("Additional sense indicates: %s\n", + additional[i].text); + + for(i=0; additional2[i].text; i++) + if(additional2[i].code1 == sense_buffer[12] && + additional2[i].code2_min >= sense_buffer[13] && + additional2[i].code2_max <= sense_buffer[13]) { + printf("Additional sense indicates: "); + printf(additional2[i].text, sense_buffer[13]); + printf("\n"); + }; + } else { /* non-extended sense data */ + + /* + * Standard says: + * sense_buffer[0] & 0200 : address valid + * sense_buffer[0] & 0177 : vendor-specific error code + * sense_buffer[1] & 0340 : vendor-specific + * sense_buffer[1..3] : 21-bit logical block address + */ + + if (leadin) + printf("%s: ", leadin); + if (sense_buffer[0] < 15) + printf("old sense: key %s\n", snstext[sense_buffer[0] & 0x0f]); + else + printf("sns = %2x %2x\n", sense_buffer[0], sense_buffer[2]); + + printf("Non-extended sense class %d code 0x%0x ", sense_class, code); + s = 4; + } + + done: + printf("Raw sense data (in hex):\n "); + for (i = 0; i < s; ++i) { + if ((i > 0) && (0 == (i % 24))) + printf("\n "); + printf("%02x ", sense_buffer[i]); + } + printf("\n"); + return; +} + +static const char * hostbyte_table[]={ +"DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", +"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", +"DID_PASSTHROUGH", "DID_SOFT_ERROR", NULL}; + +void sg_print_host_status(int host_status) +{ static int maxcode=0; + int i; + + if(! maxcode) { + for(i = 0; hostbyte_table[i]; i++) ; + maxcode = i-1; + } + printf("Host_status=0x%02x", host_status); + if(host_status > maxcode) { + printf("is invalid "); + return; + } + printf("(%s) ",hostbyte_table[host_status]); +} + +static const char * driverbyte_table[]={ +"DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR", +"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE", NULL}; + +static const char * driversuggest_table[]={"SUGGEST_OK", +"SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE", +unknown,unknown,unknown, "SUGGEST_SENSE",NULL}; + + +void sg_print_driver_status(int driver_status) +{ + static int driver_max =0 , suggest_max=0; + int i; + int dr = driver_status & SG_ERR_DRIVER_MASK; + int su = (driver_status & SG_ERR_SUGGEST_MASK) >> 4; + + if(! driver_max) { + for(i = 0; driverbyte_table[i]; i++) ; + driver_max = i; + for(i = 0; driversuggest_table[i]; i++) ; + suggest_max = i; + } + printf("Driver_status=0x%02x",driver_status); + printf(" (%s,%s) ", + dr < driver_max ? driverbyte_table[dr]:"invalid", + su < suggest_max ? driversuggest_table[su]:"invalid"); +} + +#ifdef SG_IO +int sg_chk_n_print3(const char * leadin, sg_io_hdr_t * hp) +{ + return sg_chk_n_print(leadin, hp->masked_status, hp->host_status, + hp->driver_status, hp->sbp, hp->sb_len_wr); +} +#endif + +int sg_chk_n_print(const char * leadin, int masked_status, + int host_status, int driver_status, + const unsigned char * sense_buffer, int sb_len) +{ + int done_leadin = 0; + int done_sense = 0; + + if ((0 == masked_status) && (0 == host_status) && + (0 == driver_status)) + return 1; /* No problems */ + if (0 != masked_status) { + if (leadin) + printf("%s: ", leadin); + done_leadin = 1; + sg_print_status(masked_status); + printf("\n"); + if (sense_buffer && ((masked_status == CHECK_CONDITION) || + (masked_status == COMMAND_TERMINATED))) { + sg_print_sense(0, sense_buffer, sb_len); + done_sense = 1; + } + } + if (0 != host_status) { + if (leadin && (! done_leadin)) + printf("%s: ", leadin); + if (done_leadin) + printf("plus...: "); + else + done_leadin = 1; + sg_print_host_status(host_status); + printf("\n"); + } + if (0 != driver_status) { + if (leadin && (! done_leadin)) + printf("%s: ", leadin); + if (done_leadin) + printf("plus...: "); + else + done_leadin = 1; + sg_print_driver_status(driver_status); + printf("\n"); + if (sense_buffer && (! done_sense) && + (SG_ERR_DRIVER_SENSE & driver_status)) + sg_print_sense(0, sense_buffer, sb_len); + } + return 0; +} + +#ifdef SG_IO +int sg_err_category3(sg_io_hdr_t * hp) +{ + return sg_err_category(hp->masked_status, hp->host_status, + hp->driver_status, hp->sbp, hp->sb_len_wr); +} +#endif + +int sg_err_category(int masked_status, int host_status, + int driver_status, const unsigned char * sense_buffer, + int sb_len) +{ + if ((0 == masked_status) && (0 == host_status) && + (0 == driver_status)) + return SG_ERR_CAT_CLEAN; + if ((CHECK_CONDITION == masked_status) || + (COMMAND_TERMINATED == masked_status) || + (SG_ERR_DRIVER_SENSE & driver_status)) { + if (sense_buffer && (sb_len > 2)) { + if(RECOVERED_ERROR == sense_buffer[2]) + return SG_ERR_CAT_RECOVERED; + else if ((UNIT_ATTENTION == (0x0f & sense_buffer[2])) && + (sb_len > 12)) { + if (0x28 == sense_buffer[12]) + return SG_ERR_CAT_MEDIA_CHANGED; + if (0x29 == sense_buffer[12]) + return SG_ERR_CAT_RESET; + } + } + return SG_ERR_CAT_SENSE; + } + if (0 != host_status) { + if ((SG_ERR_DID_NO_CONNECT == host_status) || + (SG_ERR_DID_BUS_BUSY == host_status) || + (SG_ERR_DID_TIME_OUT == host_status)) + return SG_ERR_CAT_TIMEOUT; + } + if (0 != driver_status) { + if (SG_ERR_DRIVER_TIMEOUT == driver_status) + return SG_ERR_CAT_TIMEOUT; + } + return SG_ERR_CAT_OTHER; +} + +int sg_get_command_size(unsigned char opcode) +{ + return COMMAND_SIZE(opcode); +} diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/sg_err.h parted-1.4.7-gpt/libparted/sg_err.h --- parted-1.4.7/libparted/sg_err.h Wed Dec 31 18:00:00 1969 +++ parted-1.4.7-gpt/libparted/sg_err.h Thu Jan 18 11:24:42 2001 @@ -0,0 +1,156 @@ + /* + libparted - a library for manipulating disk partitions + Copyright (C) 1998-2000 Free Software Foundation, Inc. + + 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 SG_ERR_H +#define SG_ERR_H +#include /* cope with silly includes */ +#include + +/* Feel free to copy and modify this GPL-ed code into your applications. */ + +/* Version 0.83 (991208) */ + + +/* Some of the following error/status codes are exchanged between the + various layers of the SCSI sub-system in Linux and should never + reach the user. They are placed here for completeness. What appears + here is copied from drivers/scsi/scsi.h which is not visible in + the user space. */ + +/* The following are 'host_status' codes */ +#ifndef DID_OK +#define DID_OK 0x00 +#endif +#ifndef DID_NO_CONNECT +#define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */ +#define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */ +#define DID_TIME_OUT 0x03 /* Timed out for some other reason */ +#define DID_BAD_TARGET 0x04 /* Bad target (id?) */ +#define DID_ABORT 0x05 /* Told to abort for some other reason */ +#define DID_PARITY 0x06 /* Parity error (on SCSI bus) */ +#define DID_ERROR 0x07 /* Internal error */ +#define DID_RESET 0x08 /* Reset by somebody */ +#define DID_BAD_INTR 0x09 /* Received an unexpected interrupt */ +#define DID_PASSTHROUGH 0x0a /* Force command past mid-level */ +#define DID_SOFT_ERROR 0x0b /* The low-level driver wants a retry */ +#endif + +/* These defines are to isolate applictaions from kernel define changes */ +#define SG_ERR_DID_OK DID_OK +#define SG_ERR_DID_NO_CONNECT DID_NO_CONNECT +#define SG_ERR_DID_BUS_BUSY DID_BUS_BUSY +#define SG_ERR_DID_TIME_OUT DID_TIME_OUT +#define SG_ERR_DID_BAD_TARGET DID_BAD_TARGET +#define SG_ERR_DID_ABORT DID_ABORT +#define SG_ERR_DID_PARITY DID_PARITY +#define SG_ERR_DID_ERROR DID_ERROR +#define SG_ERR_DID_RESET DID_RESET +#define SG_ERR_DID_BAD_INTR DID_BAD_INTR +#define SG_ERR_DID_PASSTHROUGH DID_PASSTHROUGH +#define SG_ERR_DID_SOFT_ERROR DID_SOFT_ERROR + +/* The following are 'driver_status' codes */ +#ifndef DRIVER_OK +#define DRIVER_OK 0x00 +#endif +#ifndef DRIVER_BUSY +#define DRIVER_BUSY 0x01 +#define DRIVER_SOFT 0x02 +#define DRIVER_MEDIA 0x03 +#define DRIVER_ERROR 0x04 +#define DRIVER_INVALID 0x05 +#define DRIVER_TIMEOUT 0x06 +#define DRIVER_HARD 0x07 +#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */ + +/* Following "suggests" are "or-ed" with one of previous 8 entries */ +#define SUGGEST_RETRY 0x10 +#define SUGGEST_ABORT 0x20 +#define SUGGEST_REMAP 0x30 +#define SUGGEST_DIE 0x40 +#define SUGGEST_SENSE 0x80 +#define SUGGEST_IS_OK 0xff +#endif +#ifndef DRIVER_MASK +#define DRIVER_MASK 0x0f +#endif +#ifndef SUGGEST_MASK +#define SUGGEST_MASK 0xf0 +#endif + +/* These defines are to isolate applictaions from kernel define changes */ +#define SG_ERR_DRIVER_OK DRIVER_OK +#define SG_ERR_DRIVER_BUSY DRIVER_BUSY +#define SG_ERR_DRIVER_SOFT DRIVER_SOFT +#define SG_ERR_DRIVER_MEDIA DRIVER_MEDIA +#define SG_ERR_DRIVER_ERROR DRIVER_ERROR +#define SG_ERR_DRIVER_INVALID DRIVER_INVALID +#define SG_ERR_DRIVER_TIMEOUT DRIVER_TIMEOUT +#define SG_ERR_DRIVER_HARD DRIVER_HARD +#define SG_ERR_DRIVER_SENSE DRIVER_SENSE +#define SG_ERR_SUGGEST_RETRY SUGGEST_RETRY +#define SG_ERR_SUGGEST_ABORT SUGGEST_ABORT +#define SG_ERR_SUGGEST_REMAP SUGGEST_REMAP +#define SG_ERR_SUGGEST_DIE SUGGEST_DIE +#define SG_ERR_SUGGEST_SENSE SUGGEST_SENSE +#define SG_ERR_SUGGEST_IS_OK SUGGEST_IS_OK +#define SG_ERR_DRIVER_MASK DRIVER_MASK +#define SG_ERR_SUGGEST_MASK SUGGEST_MASK + + + +/* The following "print" functions send ACSII to stdout */ +extern void sg_print_command(const unsigned char * command); +extern void sg_print_sense(const char * leadin, + const unsigned char * sense_buffer, int sb_len); +extern void sg_print_status(int masked_status); +extern void sg_print_host_status(int host_status); +extern void sg_print_driver_status(int driver_status); + +/* sg_chk_n_print() returns 1 quietly if there are no errors/warnings + else it prints to standard output and returns 0. */ +extern int sg_chk_n_print(const char * leadin, int masked_status, + int host_status, int driver_status, + const unsigned char * sense_buffer, int sb_len); +#ifdef SG_IO +extern int sg_chk_n_print3(const char * leadin, sg_io_hdr_t * hp); +#endif + + +/* The following "category" function returns one of the following */ +#define SG_ERR_CAT_CLEAN 0 /* No errors or other information */ +#define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */ +#define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */ +#define SG_ERR_CAT_TIMEOUT 3 +#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */ +#define SG_ERR_CAT_SENSE 98 /* Something else is in the sense buffer */ +#define SG_ERR_CAT_OTHER 99 /* Some other error/warning has occurred */ + +extern int sg_err_category(int masked_status, int host_status, + int driver_status, const unsigned char * sense_buffer, + int sb_len); +#ifdef SG_IO +extern int sg_err_category3(sg_io_hdr_t * hp); +#endif + + +/* Returns length of SCSI command given the opcode (first byte) */ +int sg_get_command_size(unsigned char opcode); + +#endif diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/sg_map.c parted-1.4.7-gpt/libparted/sg_map.c --- parted-1.4.7/libparted/sg_map.c Wed Dec 31 18:00:00 1969 +++ parted-1.4.7-gpt/libparted/sg_map.c Thu Jan 18 11:24:42 2001 @@ -0,0 +1,422 @@ +/* + libparted - a library for manipulating disk partitions + Copyright (C) 1998-2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* cope with silly includes */ +#include + +/* Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg") + device driver. +* Copyright (C) 2000 D. Gilbert +* 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, or (at your option) +* any later version. + + This shows the mapping from "sg" devices to other scsi devices + (i.e. sd, scd or st) if any. + Options: -n numeric scan: scan /dev/sg0,1,2, .... [default] + -a alphabetical scan: scan /dev/sga,b,c, .... + -x also show bus,chan,id,lun and type + -sd only scan for sd devices (disks) + -st only scan for st devices (tapes) + -scd (or -sr) only scan for scd devices (cdroms) + + Note: This program requires sg version 2 or better. + + Version 0.12 20000415 +*/ + +#include "sg_map.h" + +struct _sg_to_sd sg_to_sd[MAX_SG_DEVS]; + +#ifndef SG_GET_RESERVED_SIZE +#error "Need version 2 sg driver (linux kernel >= 2.2.6)" +#endif + +static const char * devfs_id = "/dev/.devfsd"; + +#define NUMERIC_SCAN_DEF 1 /* change to 0 to make alpha scan default */ + + +typedef struct my_map_info +{ + int active; + int lin_dev_type; + int oth_dev_num; + struct sg_scsi_id sg_dat; +} my_map_info_t; + + +#define MAX_SG_DEVS 128 +#define MAX_SD_DEVS 128 +#define MAX_SR_DEVS 128 +#define MAX_ST_DEVS 128 +#define MAX_ERRORS 4 + +static my_map_info_t map_arr[MAX_SG_DEVS]; + +#define LIN_DEV_TYPE_UNKNOWN 0 +#define LIN_DEV_TYPE_SD 1 +#define LIN_DEV_TYPE_SR 2 +#define LIN_DEV_TYPE_ST 3 +#define LIN_DEV_TYPE_SCD 4 + + +typedef struct my_scsi_idlun { +/* why can't userland see this structure ??? */ + int dev_id; + int host_unique_id; +} My_scsi_idlun; + + +#define EBUFF_LEN 256 +static char ebuff[EBUFF_LEN]; + +static void scan_dev_type(const char * leadin, int max_dev, int do_numeric, + int lin_dev_type, int last_sg_ind); + +static void usage() +{ + printf("Usage: 'sg_map [-a] [-n] [-x] [-sd] [-scd or -sr] [-st]'\n"); + printf(" where: -a do alphabetic scan (ie sga, sgb, sgc)\n"); + printf(" -n do numeric scan (ie sg0, sg1, sg2)\n"); + printf(" -x also show bus,chan,id,lun and type\n"); + printf(" -sd show mapping to disks\n"); + printf(" -scd show mapping to cdroms (look for /dev/scd\n"); + printf(" -sr show mapping to cdroms (look for /dev/sr\n"); + printf(" -st show mapping to tapes\n"); + printf(" If no '-s*' arguments given then show all mappings\n"); +} + + +static void make_dev_name(char * fname, const char * leadin, int k, + int do_numeric) +{ + char buff[64]; + int big,little; + + strcpy(fname, leadin ? leadin : "/dev/sg"); + if (do_numeric) { + sprintf(buff, "%d", k); + strcat(fname, buff); + } + else { + if (k < 26) { + buff[0] = 'a' + (char)k; + buff[1] = '\0'; + strcat(fname, buff); + } + else if (k <= 255) { /* assumes sequence goes x,y,z,aa,ab,ac etc */ + big = k/26; + little = k - (26 * big); + big = big - 1; + + buff[0] = 'a' + (char)big; + buff[1] = 'a' + (char)little; + buff[2] = '\0'; + strcat(fname, buff); + } + else + strcat(fname, "xxxx"); + } +} + +int sg_to_sd_map_made = 0; + +int +make_sg_to_sd_map() +{ + int sg_fd, res, k; + int do_numeric = NUMERIC_SCAN_DEF; + int do_all_s = 0; + int do_sd = 1; + int do_st = 0; + int do_sr = 0; + int do_scd = 0; + int do_extra = 0; + char fname[64]; + int num_errors = 0; + int num_silent = 0; + int eacces_err = 0; + int last_sg_ind = -1; + struct stat stat_buf; + + memset(&sg_to_sd, 0, MAX_SG_DEVS * sizeof(struct _sg_to_sd)); + +#if 0 + for (k = 1; k < argc; ++k) { + if (0 == strcmp("-n", argv[k])) + do_numeric = 1; + else if (0 == strcmp("-a", argv[k])) + do_numeric = 0; + else if (0 == strcmp("-x", argv[k])) + do_extra = 1; + else if (0 == strcmp("-sd", argv[k])) { + do_sd = 1; + do_all_s = 0; + } + else if (0 == strcmp("-st", argv[k])) { + do_st = 1; + do_all_s = 0; + } + else if (0 == strcmp("-sr", argv[k])) { + do_sr = 1; + do_all_s = 0; + } + else if (0 == strcmp("-scd", argv[k])) { + do_scd = 1; + do_all_s = 0; + } + else if ((0 == strcmp("-?", argv[k])) || + (0 == strncmp("-h", argv[k], 2))) { + printf( + "Show mapping from sg devices to other scsi device names\n\n"); + usage(); + return 1; + } + else if (*argv[k] == '-') { + printf("Unknown switch: %s\n", argv[k]); + usage(); + return 1; + } + else if (*argv[k] != '-') { + printf("Unknown argument\n"); + usage(); + return 1; + } + } +#endif + + if (stat(devfs_id, &stat_buf) == 0) + printf("# Note: the devfs pseudo file system is present\n"); + + for (k = 0, res = 0; (k < MAX_SG_DEVS) && (num_errors < MAX_ERRORS); + ++k, res = (sg_fd >= 0) ? close(sg_fd) : 0) { + if (res < 0) { + sprintf(ebuff, "Error closing %s ", fname); + perror("sg_map: close error"); + return 1; + } + make_dev_name(fname, "/dev/sg", k, do_numeric); + + sg_fd = open(fname, O_RDONLY | O_NONBLOCK); + if (sg_fd < 0) { + if (EBUSY == errno) { + map_arr[k].active = -2; + continue; + } + else if ((ENODEV == errno) || (ENOENT == errno) || + (ENXIO == errno)) { + ++num_errors; + ++num_silent; + map_arr[k].active = -1; + continue; + } + else { + if (EACCES == errno) + eacces_err = 1; + sprintf(ebuff, "Error opening %s ", fname); + perror(ebuff); + ++num_errors; + continue; + } + } + res = ioctl(sg_fd, SG_GET_SCSI_ID, &map_arr[k].sg_dat); + if (res < 0) { + sprintf(ebuff, "device %s failed on sg ioctl, skip", fname); + perror(ebuff); + ++num_errors; + continue; + } + map_arr[k].active = 1; + map_arr[k].oth_dev_num = -1; + last_sg_ind = k; + } + if ((num_errors >= MAX_ERRORS) && (num_silent < num_errors)) { + printf("Stopping because there are too many error\n"); + if (eacces_err) + printf(" root access may be required\n"); + return 1; + } + if (last_sg_ind < 0) { + printf("Stopping because no sg devices found\n"); + } + + if (do_all_s || do_sd) + scan_dev_type("/dev/sd", MAX_SD_DEVS, 0, LIN_DEV_TYPE_SD, last_sg_ind); +#if 0 + if (do_all_s || do_sr) + scan_dev_type("/dev/sr", MAX_SR_DEVS, 1, LIN_DEV_TYPE_SR, last_sg_ind); + if (do_all_s || do_scd) + scan_dev_type("/dev/scd", MAX_SR_DEVS, 1, LIN_DEV_TYPE_SCD, + last_sg_ind); + if (do_all_s || do_st) + scan_dev_type("/dev/st", MAX_ST_DEVS, 1, LIN_DEV_TYPE_ST, last_sg_ind); +#endif + + for (k = 0; k <= last_sg_ind; ++k) { + make_dev_name(fname, "/dev/sg", k, do_numeric); + // printf("%s", fname); + snprintf(sg_to_sd[k].sg, 15, "%s", fname); + switch (map_arr[k].active) + { + case -2: + printf(do_extra ? " -2 -2 -2 -2 -2" : " busy"); + break; + case -1: + printf(do_extra ? " -1 -1 -1 -1 -1" : " not present"); + break; + case 0: + printf(do_extra ? " -3 -3 -3 -3 -3" : " some error\n"); + break; + case 1: + if (do_extra) + printf(" %d %d %d %d %d", map_arr[k].sg_dat.host_no, + map_arr[k].sg_dat.channel, map_arr[k].sg_dat.scsi_id, + map_arr[k].sg_dat.lun, map_arr[k].sg_dat.scsi_type); + switch (map_arr[k].lin_dev_type) + { + case LIN_DEV_TYPE_SD: + make_dev_name(fname, "/dev/sd" , map_arr[k].oth_dev_num, 0); + // printf(" %s", fname); + snprintf(sg_to_sd[k].sd, 15, "%s", fname); + break; +#if 0 + case LIN_DEV_TYPE_ST: + make_dev_name(fname, "/dev/st" , map_arr[k].oth_dev_num, 1); + printf(" %s", fname); + break; + case LIN_DEV_TYPE_SR: + make_dev_name(fname, "/dev/sr" , map_arr[k].oth_dev_num, 1); + printf(" %s", fname); + break; + case LIN_DEV_TYPE_SCD: + make_dev_name(fname, "/dev/scd" , map_arr[k].oth_dev_num, 1); + printf(" %s", fname); + break; +#endif + default: + break; + } + break; + default: + printf(" bad logic\n"); + break; + } + // printf("\n"); + } + + sg_to_sd_map_made = 1; + return 0; +} + +static int find_dev_in_sg_arr(My_scsi_idlun * my_idlun, int host_no, + int last_sg_ind) +{ + int k; + struct sg_scsi_id * sidp; + + for (k = 0; k <= last_sg_ind; ++k) { + sidp = &(map_arr[k].sg_dat); + if ((host_no == sidp->host_no) && + ((my_idlun->dev_id & 0xff) == sidp->scsi_id) && + (((my_idlun->dev_id >> 8) & 0xff) == sidp->lun) && + (((my_idlun->dev_id >> 16) & 0xff) == sidp->channel)) + return k; + } + return -1; +} + +static void scan_dev_type(const char * leadin, int max_dev, int do_numeric, + int lin_dev_type, int last_sg_ind) +{ + int k, res, ind, sg_fd; + int num_errors = 0; + int num_silent = 0; + int host_no = -1; + My_scsi_idlun my_idlun; + char fname[64]; + + for (k = 0, res = 0; (k < max_dev) && (num_errors < MAX_ERRORS); + ++k, res = (sg_fd >= 0) ? close(sg_fd) : 0) { + if (res < 0) { + sprintf(ebuff, "Error closing %s ", fname); + perror("sg_map: close error"); + return; + } + make_dev_name(fname, leadin, k, do_numeric); + + sg_fd = open(fname, O_RDONLY | O_NONBLOCK); + if (sg_fd < 0) { + if (EBUSY == errno) { + printf("Device %s is busy\n", fname); + ++num_errors; + continue; + } + else if ((ENODEV == errno) || (ENOENT == errno) || + (ENXIO == errno)) { + ++num_errors; + ++num_silent; + continue; + } + else { + sprintf(ebuff, "Error opening %s ", fname); + perror(ebuff); + ++num_errors; + continue; + } + } + + res = ioctl(sg_fd, SCSI_IOCTL_GET_IDLUN, &my_idlun); + if (res < 0) { + sprintf(ebuff, "device %s failed on scsi ioctl(idlun), skip", + fname); + perror(ebuff); + ++num_errors; + continue; + } + res = ioctl(sg_fd, SCSI_IOCTL_GET_BUS_NUMBER, &host_no); + if (res < 0) { + sprintf(ebuff, "device %s failed on scsi ioctl(bus_number), skip", + fname); + perror(ebuff); + ++num_errors; + continue; + } + ind = find_dev_in_sg_arr(&my_idlun, host_no, last_sg_ind); + if (ind >= 0) { + map_arr[ind].oth_dev_num = k; + map_arr[ind].lin_dev_type = lin_dev_type; + } + else + printf("Strange, could not find device %s mapped to sg device??\n", + fname); + } +} + diff -BburN --exclude *.orig --exclude *.spec --exclude=*Makefile.in --exclude=*.po* parted-1.4.7/libparted/sg_map.h parted-1.4.7-gpt/libparted/sg_map.h --- parted-1.4.7/libparted/sg_map.h Wed Dec 31 18:00:00 1969 +++ parted-1.4.7-gpt/libparted/sg_map.h Thu Jan 18 11:24:42 2001 @@ -0,0 +1,33 @@ + /* + libparted - a library for manipulating disk partitions + Copyright (C) 1998-2000 Free Software Foundation, Inc. + + 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 MAX_SG_DEVS 128 + + +struct _sg_to_sd { + char sg[16]; + char sd[16]; +}; + + +extern struct _sg_to_sd sg_to_sd[MAX_SG_DEVS]; +extern int sg_to_sd_map_made; + +int make_sg_to_sd_map(); +