- sfdisk warning for large partitions, gpt --- util-linux-2.13-pre6/fdisk/fdisk.c.gpt 2005-11-24 15:30:36.000000000 +0100 +++ util-linux-2.13-pre6/fdisk/fdisk.c 2005-11-24 15:30:36.000000000 +0100 @@ -34,6 +34,8 @@ #include #endif +#include "gpt.h" + static void delete_partition(int i); #define hex_val(c) ({ \ @@ -2400,6 +2402,14 @@ } static void +gpt_warning(char *dev) +{ + if (gpt_probe_signature_devname(dev)) + fprintf(stderr, _("\nWARNING: GPT (GUID Partition Table) detected on '%s'! " + "The util fdisk doesn't support GPT. Use GNU Parted.\n\n"), dev); +} + +static void try(char *device, int user_specified) { int gb; @@ -2409,6 +2419,7 @@ if (!user_specified) if (is_ide_cdrom_or_tape(device)) return; + gpt_warning(device); if ((fd = open(disk_device, type_open)) >= 0) { gb = get_boot(try_only); if (gb > 0) { /* I/O error */ @@ -2470,6 +2481,8 @@ printf(_("%c: unknown command\n"), c); } + + int main(int argc, char **argv) { int j, c; @@ -2574,6 +2587,7 @@ for (j = optind; j < argc; j++) { disk_device = argv[j]; + gpt_warning(disk_device); if ((fd = open(disk_device, type_open)) < 0) fatal(unable_to_open); if (disksize(fd, &size)) @@ -2594,6 +2608,7 @@ else fatal(usage2); + gpt_warning(disk_device); get_boot(fdisk); if (osf_label) { --- /dev/null 2005-11-14 15:52:26.044616250 +0100 +++ util-linux-2.13-pre6/fdisk/gpt.h 2005-11-24 15:30:36.000000000 +0100 @@ -0,0 +1,9 @@ + +#ifndef __GPT_H__ +#define __GPT_H__ + +extern int gpt_probe_signature_fd(int fd); +extern int gpt_probe_signature_devname(char *devname); + +#endif /* __GPT_H__ */ + --- util-linux-2.13-pre6/fdisk/Makefile.am.gpt 2005-10-16 14:12:52.000000000 +0200 +++ util-linux-2.13-pre6/fdisk/Makefile.am 2005-11-24 15:31:42.000000000 +0100 @@ -5,13 +5,13 @@ sbin_PROGRAMS = fdisk man_MANS = fdisk.8 fdisk_SOURCES = fdisk.c disksize.c fdiskbsdlabel.c fdisksgilabel.c \ - fdisksunlabel.c fdiskaixlabel.c i386_sys_types.c partname.c + fdisksunlabel.c fdiskaixlabel.c i386_sys_types.c partname.c gpt.c if !SPARC sbin_PROGRAMS += sfdisk man_MANS += sfdisk.8 -sfdisk_SOURCES = sfdisk.c disksize.c i386_sys_types.c partname.c +sfdisk_SOURCES = sfdisk.c disksize.c i386_sys_types.c partname.c gpt.c if USE_SLANG sbin_PROGRAMS += cfdisk --- util-linux-2.13-pre6/fdisk/fdisk.8.gpt 2005-11-24 15:30:36.000000000 +0100 +++ util-linux-2.13-pre6/fdisk/fdisk.8 2005-11-24 15:30:36.000000000 +0100 @@ -42,6 +42,11 @@ partition tables. It understands DOS type partition tables and BSD or SUN type disklabels. +.B fdisk +doesn't understand GUID Partition Table (GPT) and +it is not designed for large partitions. In particular case use more advanced GNU +.B parted(8). + The .I device is usually one of the following: --- util-linux-2.13-pre6/fdisk/sfdisk.8.gpt 2004-12-31 17:28:30.000000000 +0100 +++ util-linux-2.13-pre6/fdisk/sfdisk.8 2005-11-24 15:30:36.000000000 +0100 @@ -18,6 +18,11 @@ on a device, check the partitions on a device, and - very dangerous - repartition a device. +.B sfdisk +doesn't understand GUID Partition Table (GPT) and +it is not designed for large partitions. In particular case use more advanced GNU +.B parted(8). + .SS "List Sizes" .BI "sfdisk \-s " partition gives the size of --- /dev/null 2005-11-14 15:52:26.044616250 +0100 +++ util-linux-2.13-pre6/fdisk/gpt.c 2005-11-24 15:30:36.000000000 +0100 @@ -0,0 +1,287 @@ +/* + GPT (GUID Partition Table) signature detection. Based on libparted and + util-linux/partx. + + Warning: this code doesn't do all GPT checks (CRC32, Protective MBR, ..). It's + really GPT signature detection only. + + -- Karel Zak (Jun-2-2005) + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gpt.h" + +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#define SECTOR_SIZE 512 /* default */ + +#define _GET_BYTE(x, n) ( ((x) >> (8 * (n))) & 0xff ) + +#define _PED_SWAP64(x) ( (_GET_BYTE(x, 0) << 56) \ + + (_GET_BYTE(x, 1) << 48) \ + + (_GET_BYTE(x, 2) << 40) \ + + (_GET_BYTE(x, 3) << 32) \ + + (_GET_BYTE(x, 4) << 24) \ + + (_GET_BYTE(x, 5) << 16) \ + + (_GET_BYTE(x, 6) << 8) \ + + (_GET_BYTE(x, 7) << 0) ) + +#define PED_SWAP64(x) ((uint64_t) _PED_SWAP64( (uint64_t) (x) )) + +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define CPU_TO_LE64(x) (x) +#else +# define CPU_TO_LE64(x) PED_SWAP64(x) +#endif + +#define BLKSSZGET _IO(0x12,104) /* get block device sector size */ +#define BLKGETLASTSECT _IO(0x12,108) /* get last sector of block device */ +#define BLKGETSIZE _IO(0x12,96) /* return device size */ +#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */ + +#define GPT_HEADER_SIGNATURE 0x5452415020494645LL +#define GPT_PRIMARY_PARTITION_TABLE_LBA 1 + +typedef struct { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_hi_and_reserved; + uint8_t clock_seq_low; + uint8_t node[6]; +} /* __attribute__ ((packed)) */ efi_guid_t; +/* commented out "__attribute__ ((packed))" to work around gcc bug (fixed + * in gcc3.1): __attribute__ ((packed)) breaks addressing on initialized + * data. It turns out we don't need it in this case, so it doesn't break + * anything :) + */ + +typedef struct _GuidPartitionTableHeader_t { + uint64_t Signature; + uint32_t Revision; + uint32_t HeaderSize; + uint32_t HeaderCRC32; + uint32_t Reserved1; + uint64_t MyLBA; + uint64_t AlternateLBA; + uint64_t FirstUsableLBA; + uint64_t LastUsableLBA; + efi_guid_t DiskGUID; + uint64_t PartitionEntryLBA; + uint32_t NumberOfPartitionEntries; + uint32_t SizeOfPartitionEntry; + uint32_t PartitionEntryArrayCRC32; + uint8_t Reserved2[512 - 92]; +} __attribute__ ((packed)) GuidPartitionTableHeader_t; + +struct blkdev_ioctl_param { + unsigned int block; + size_t content_length; + char * block_contents; +}; + +static int +_get_linux_version (void) +{ + static int kver = -1; + struct utsname uts; + int major; + int minor; + int teeny; + + if (kver != -1) + return kver; + if (uname (&uts)) + return kver = 0; + if (sscanf (uts.release, "%u.%u.%u", &major, &minor, &teeny) != 3) + return kver = 0; + return kver = KERNEL_VERSION (major, minor, teeny); +} + +static unsigned int +_get_sector_size (int fd) +{ + unsigned int sector_size; + + if (_get_linux_version() < KERNEL_VERSION (2,3,0)) + return SECTOR_SIZE; + if (ioctl (fd, BLKSSZGET, §or_size)) + return SECTOR_SIZE; + return sector_size; +} + +static uint64_t +_get_num_sectors(int fd) +{ + int version = _get_linux_version(); + unsigned long size; + uint64_t bytes=0; + + if (version >= KERNEL_VERSION(2,5,4) || + (version < KERNEL_VERSION(2,5,0) && + version >= KERNEL_VERSION (2,4,18))) + { + if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) + return bytes / _get_sector_size(fd); + } + if (ioctl (fd, BLKGETSIZE, &size)) + return 0; + return size; +} + +static uint64_t +last_lba(int fd) +{ + int rc; + uint64_t sectors = 0; + struct stat s; + + memset(&s, 0, sizeof (s)); + rc = fstat(fd, &s); + if (rc == -1) + { + fprintf(stderr, "last_lba() could not stat: %s\n", + strerror(errno)); + return 0; + } + if (S_ISBLK(s.st_mode)) + sectors = _get_num_sectors(fd); + else + { + fprintf(stderr, + "last_lba(): I don't know how to handle files with mode %x\n", + s.st_mode); + sectors = 1; + } + return sectors - 1; +} + +static ssize_t +read_lastoddsector(int fd, uint64_t lba, void *buffer, size_t count) +{ + int rc; + struct blkdev_ioctl_param ioctl_param; + + if (!buffer) return 0; + + ioctl_param.block = 0; /* read the last sector */ + ioctl_param.content_length = count; + ioctl_param.block_contents = buffer; + + rc = ioctl(fd, BLKGETLASTSECT, &ioctl_param); + if (rc == -1) perror("read failed"); + + return !rc; +} + +static ssize_t +read_lba(int fd, uint64_t lba, void *buffer, size_t bytes) +{ + int sector_size = _get_sector_size(fd); + off_t offset = lba * sector_size; + ssize_t bytesread; + + lseek(fd, offset, SEEK_SET); + bytesread = read(fd, buffer, bytes); + + /* Kludge. This is necessary to read/write the last + block of an odd-sized disk, until Linux 2.5.x kernel fixes. + This is only used by gpt.c, and only to read + one sector, so we don't have to be fancy. + */ + if (!bytesread && !(last_lba(fd) & 1) && lba == last_lba(fd)) + bytesread = read_lastoddsector(fd, lba, buffer, bytes); + return bytesread; +} + +static GuidPartitionTableHeader_t * +alloc_read_gpt_header(int fd, uint64_t lba) +{ + GuidPartitionTableHeader_t *gpt = + (GuidPartitionTableHeader_t *) malloc(sizeof (GuidPartitionTableHeader_t)); + if (!gpt) + return NULL; + memset(gpt, 0, sizeof (*gpt)); + if (!read_lba(fd, lba, gpt, sizeof (GuidPartitionTableHeader_t))) + { + free(gpt); + return NULL; + } + return gpt; +} + +static int +gpt_check_signature(int fd, uint64_t lba) +{ + GuidPartitionTableHeader_t *gpt; + int res=0; + + if ((gpt = alloc_read_gpt_header(fd, lba))) + { + if (gpt->Signature == CPU_TO_LE64(GPT_HEADER_SIGNATURE)) + res = 1; + free(gpt); + } + return res; +} + +/* returns: + * 0 not found GPT + * 1 for valid primary GPT header + * 2 for valid alternative GPT header + */ +int +gpt_probe_signature_fd(int fd) +{ + int res = 0; + + /* check primary GPT header */ + if (gpt_check_signature(fd, GPT_PRIMARY_PARTITION_TABLE_LBA)) + res = 1; + else + { + /* check alternative GPT header */ + uint64_t lastlba = last_lba(fd); + if (gpt_check_signature(fd, lastlba)) + res = 2; + } + return res; +} + +int +gpt_probe_signature_devname(char *devname) +{ + int res, fd; + if ((fd = open(devname, O_RDONLY)) < 0) + return 0; + res = gpt_probe_signature_fd(fd); + close(fd); + return res; +} + +#ifdef GPT_TEST_MAIN +int +main(int argc, char **argv) +{ + if (argc!=2) + { + fprintf(stderr, "usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + if (gpt_probe_signature_devname(argv[1])) + printf("GPT (GUID Partition Table) detected on %s\n", argv[1]); + exit(EXIT_SUCCESS); +} +#endif --- util-linux-2.13-pre6/fdisk/sfdisk.c.gpt 2005-10-16 14:18:32.000000000 +0200 +++ util-linux-2.13-pre6/fdisk/sfdisk.c 2005-11-24 15:30:36.000000000 +0100 @@ -50,6 +50,8 @@ #include "nls.h" #include "common.h" +#include "gpt.h" + #define SIZE(a) (sizeof(a)/sizeof(a[0])) /* @@ -2457,6 +2459,23 @@ return NULL; } +static void +gpt_warning(char *dev, int warn_only) +{ + if (force) + warn_only = 1; + + if (gpt_probe_signature_devname(dev)) { + fflush(stdout); + fprintf(stderr, _("\nWARNING: GPT (GUID Partition Table) detected on '%s'! " + "The util sfdisk doesn't support GPT. Use GNU Parted.\n\n"), dev); + if (!warn_only) { + fprintf(stderr, _("Use the --force flag to overrule this check.\n")); + exit(1); + } + } +} + static void do_list(char *dev, int silent); static void do_size(char *dev, int silent); static void do_geom(char *dev, int silent); @@ -2602,6 +2621,7 @@ while ((dev = nextproc()) != NULL) { if (is_ide_cdrom_or_tape(dev)) continue; + gpt_warning(dev, 1); if (opt_out_geom) do_geom(dev, 1); if (opt_out_pt_geom) @@ -2629,6 +2649,7 @@ if (opt_list || opt_out_geom || opt_out_pt_geom || opt_size || verify) { while (optind < argc) { + gpt_warning(argv[optind], 1); if (opt_out_geom) do_geom(argv[optind], 0); if (opt_out_pt_geom) @@ -2657,6 +2678,7 @@ fatal(_("usage: sfdisk --change-id device partition-number Id\n")); else if (optind != argc-3 && optind != argc-2) fatal(_("usage: sfdisk --id device partition-number [Id]\n")); + gpt_warning(argv[optind], 0); do_change_id(argv[optind], argv[optind+1], (optind == argc-2) ? 0 : argv[optind+2]); exit(exit_status); @@ -2666,6 +2688,8 @@ fatal(_("can specify only one device (except with -l or -s)\n")); dev = argv[optind]; + gpt_warning(dev, 0); + if (opt_reread) do_reread(dev); else if (restore_sector_file) @@ -2842,6 +2866,8 @@ z = &oldp; + gpt_warning(dev, 0); + rw = (!no_write && (arg || ac > 1)); fd = my_open(dev, rw, 0); @@ -2943,6 +2969,8 @@ z = &oldp; + gpt_warning(dev, 0); + rw = !no_write; fd = my_open(dev, rw, 0);