fdisk: make it work with big disks (read: typical today's disks)
authorDenis Vlasenko <vda.linux@googlemail.com>
Sat, 2 Jun 2007 12:46:55 +0000 (12:46 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sat, 2 Jun 2007 12:46:55 +0000 (12:46 -0000)
even if CONFIG_LFS is unset.

util-linux/fdisk.c

index a1893c6..ed5abe9 100644 (file)
@@ -7,6 +7,10 @@
  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
  */
 
+#ifndef _LARGEFILE64_SOURCE
+/* For lseek64 */
+#define _LARGEFILE64_SOURCE
+#endif
 #include <assert.h>             /* assert */
 #include "libbb.h"
 
@@ -34,6 +38,9 @@
 #define LINUX_LVM       0x8e
 #define LINUX_RAID      0xfd
 
+/* Used for sector numbers. Today's disk sizes make it necessary */
+typedef unsigned long long ullong;
+
 struct hd_geometry {
        unsigned char heads;
        unsigned char sectors;
@@ -77,10 +84,12 @@ struct partition {
        unsigned char size4[4];         /* nr of sectors in partition */
 } ATTRIBUTE_PACKED;
 
-enum failure {
-       ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
-       unable_to_write
-};
+static const char unable_to_open[] = "cannot open %s";
+static const char unable_to_read[] = "cannot read from %s";
+static const char unable_to_seek[] = "cannot seek on %s";
+static const char unable_to_write[] = "cannot write to %s";
+static const char ioctl_error[] = "BLKGETSIZE ioctl failed on %s";
+static void fdisk_fatal(const char *why) ATTRIBUTE_NORETURN;
 
 enum label_type {
        label_dos, label_sun, label_sgi, label_aix, label_osf
@@ -138,7 +147,6 @@ static void list_types(const char *const *sys);
 static unsigned read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg);
 #endif
 static const char *partition_type(unsigned char type);
-static void fdisk_fatal(enum failure why) ATTRIBUTE_NORETURN;
 static void get_geometry(void);
 static int get_boot(enum action what);
 
@@ -159,7 +167,7 @@ static unsigned get_nr_sects(const struct partition *p);
 struct pte {
        struct partition *part_table;   /* points into sectorbuffer */
        struct partition *ext_pointer;  /* points into sectorbuffer */
-       off_t offset;           /* disk sector number */
+       ullong offset;          /* disk sector number */
        char *sectorbuffer;     /* disk sector contents */
 #if ENABLE_FEATURE_FDISK_WRITABLE
        char changed;           /* boolean */
@@ -604,69 +612,41 @@ get_nr_sects(const struct partition *p)
 /* normally O_RDWR, -l option gives O_RDONLY */
 static int type_open = O_RDWR;
 
-
 static int ext_index;               /* the prime extended partition */
-static int listing;                    /* no aborts for fdisk -l */
+static int listing;                 /* no aborts for fdisk -l */
 static int dos_compatible_flag = ~0;
 #if ENABLE_FEATURE_FDISK_WRITABLE
 static int dos_changed;
 static int nowarn;            /* no warnings for fdisk -l/-s */
 #endif
 
-
-
 static unsigned user_cylinders, user_heads, user_sectors;
 static unsigned pt_heads, pt_sectors;
 static unsigned kern_heads, kern_sectors;
 
-static off_t extended_offset;            /* offset of link pointers */
-
-static unsigned long long total_number_of_sectors;
+static ullong extended_offset;            /* offset of link pointers */
+static ullong total_number_of_sectors;
 
-
-static void fdisk_fatal(enum failure why)
+static void fdisk_fatal(const char *why)
 {
-       const char *message;
-
        if (listing) {
                close(fd);
                longjmp(listingbuf, 1);
        }
-
-       switch (why) {
-       case unable_to_open:
-               message = "cannot open %s";
-               break;
-       case unable_to_read:
-               message = "cannot read from %s";
-               break;
-       case unable_to_seek:
-               message = "cannot seek on %s";
-               break;
-       case unable_to_write:
-               message = "cannot write to %s";
-               break;
-       case ioctl_error:
-               message = "BLKGETSIZE ioctl failed on %s";
-               break;
-       default:
-               message = "fatal error";
-       }
-
-       bb_error_msg_and_die(message, disk_device);
+       bb_error_msg_and_die(why, disk_device);
 }
 
 static void
-seek_sector(off_t secno)
+seek_sector(ullong secno)
 {
-       off_t offset = secno * sector_size;
-       if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
+       secno *= sector_size;
+       if (lseek64(fd, (off64_t)secno, SEEK_SET) == (off64_t) -1)
                fdisk_fatal(unable_to_seek);
 }
 
 #if ENABLE_FEATURE_FDISK_WRITABLE
 static void
-write_sector(off_t secno, char *buf)
+write_sector(ullong secno, char *buf)
 {
        seek_sector(secno);
        if (write(fd, buf, sector_size) != sector_size)
@@ -676,7 +656,7 @@ write_sector(off_t secno, char *buf)
 
 /* Allocate a buffer and read a partition table sector */
 static void
-read_pte(struct pte *pe, off_t offset)
+read_pte(struct pte *pe, ullong offset)
 {
        pe->offset = offset;
        pe->sectorbuffer = xmalloc(sector_size);
@@ -928,10 +908,10 @@ clear_partition(struct partition *p)
 
 #if ENABLE_FEATURE_FDISK_WRITABLE
 static void
-set_partition(int i, int doext, off_t start, off_t stop, int sysid)
+set_partition(int i, int doext, ullong start, ullong stop, int sysid)
 {
        struct partition *p;
-       off_t offset;
+       ullong offset;
 
        if (doext) {
                p = ptes[i].ext_pointer;
@@ -1182,7 +1162,7 @@ static void
 get_geometry(void)
 {
        int sec_fac;
-       unsigned long long bytes;       /* really u64 */
+       uint64_t v64;
 
        get_sectorsize();
        sec_fac = sector_size / 512;
@@ -1202,18 +1182,16 @@ get_geometry(void)
        sectors = user_sectors ? user_sectors :
                pt_sectors ? pt_sectors :
                kern_sectors ? kern_sectors : 63;
-       if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
-               /* got bytes */
+       if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
+               /* got bytes, convert to 512 byte sectors */
+               total_number_of_sectors = (v64 >> 9);
        } else {
-               unsigned long longsectors;
-
-       if (ioctl(fd, BLKGETSIZE, &longsectors))
-               longsectors = 0;
-               bytes = ((unsigned long long) longsectors) << 9;
+               unsigned long longsectors; /* need temp of type long */
+               if (ioctl(fd, BLKGETSIZE, &longsectors))
+                       longsectors = 0;
+               total_number_of_sectors = longsectors;
        }
 
-       total_number_of_sectors = (bytes >> 9);
-
        sector_offset = 1;
        if (dos_compatible_flag)
                sector_offset = sectors;
@@ -1447,10 +1425,10 @@ read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *
                                break;
                        }
                        if (absolute) {
-                               unsigned long long bytes;
+                               ullong bytes;
                                unsigned long unit;
 
-                               bytes = (unsigned long long) i * absolute;
+                               bytes = (ullong) i * absolute;
                                unit = sector_size * units_per_sector;
                                bytes += unit/2; /* round */
                                bytes /= unit;
@@ -1844,7 +1822,7 @@ wrong_p_order(int *prev)
 {
        const struct pte *pe;
        const struct partition *p;
-       off_t last_p_start_pos = 0, p_start_pos;
+       ullong last_p_start_pos = 0, p_start_pos;
        int i, last_i = 0;
 
        for (i = 0 ; i < partitions; i++) {
@@ -2012,8 +1990,8 @@ list_table(int xtra)
 
        for (i = 0; i < partitions; i++) {
                const struct pte *pe = &ptes[i];
-               off_t psects;
-               off_t pblocks;
+               ullong psects;
+               ullong pblocks;
                unsigned podd;
 
                p = pe->part_table;
@@ -2035,10 +2013,10 @@ list_table(int xtra)
                        partname(disk_device, i+1, w+2),
                        !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
                                ? '*' : '?',
-                       (unsigned long long) cround(get_partition_start(pe)),           /* start */
-                       (unsigned long long) cround(get_partition_start(pe) + psects    /* end */
+                       (ullong) cround(get_partition_start(pe)),           /* start */
+                       (ullong) cround(get_partition_start(pe) + psects    /* end */
                                - (psects ? 1 : 0)),
-                       (unsigned long long) pblocks, podd ? '+' : ' ', /* odd flag on end */
+                       (ullong) pblocks, podd ? '+' : ' ', /* odd flag on end */
                        p->sys_ind,                                     /* type id */
                        partition_type(p->sys_ind));                    /* type name */
 
@@ -2085,7 +2063,7 @@ x_list_table(int extend)
 
 #if ENABLE_FEATURE_FDISK_WRITABLE
 static void
-fill_bounds(off_t *first, off_t *last)
+fill_bounds(ullong *first, ullong *last)
 {
        int i;
        const struct pte *pe = &ptes[0];
@@ -2104,9 +2082,9 @@ fill_bounds(off_t *first, off_t *last)
 }
 
 static void
-check(int n, unsigned h, unsigned s, unsigned c, off_t start)
+check(int n, unsigned h, unsigned s, unsigned c, ullong start)
 {
-       off_t total, real_s, real_c;
+       ullong total, real_s, real_c;
 
        real_s = sector(s) - 1;
        real_c = cylinder(s, c);
@@ -2120,11 +2098,11 @@ check(int n, unsigned h, unsigned s, unsigned c, off_t start)
                printf("Partition %d: sector %d greater than "
                        "maximum %d\n", n, s, sectors);
        if (real_c >= cylinders)
-               printf("Partition %d: cylinder %"OFF_FMT"u greater than "
+               printf("Partition %d: cylinder %llu greater than "
                        "maximum %d\n", n, real_c + 1, cylinders);
        if (cylinders <= 1024 && start != total)
-               printf("Partition %d: previous sectors %"OFF_FMT"u disagrees with "
-                       "total %"OFF_FMT"u\n", n, start, total);
+               printf("Partition %d: previous sectors %llu disagrees with "
+                       "total %llu\n", n, start, total);
 }
 
 static void
@@ -2132,7 +2110,7 @@ verify(void)
 {
        int i, j;
        unsigned total = 1;
-       off_t first[partitions], last[partitions];
+       ullong first[partitions], last[partitions];
        struct partition *p;
 
        if (warn_geometry())
@@ -2176,7 +2154,7 @@ verify(void)
 
        if (extended_offset) {
                struct pte *pex = &ptes[ext_index];
-               off_t e_last = get_start_sect(pex->part_table) +
+               ullong e_last = get_start_sect(pex->part_table) +
                        get_nr_sects(pex->part_table) - 1;
 
                for (i = 4; i < partitions; i++) {
@@ -2210,9 +2188,9 @@ add_partition(int n, int sys)
        int i, num_read = 0;
        struct partition *p = ptes[n].part_table;
        struct partition *q = ptes[ext_index].part_table;
-       long long llimit;
-       off_t start, stop = 0, limit, temp,
-               first[partitions], last[partitions];
+       ullong limit, temp;
+       ullong start, stop = 0;
+       ullong first[partitions], last[partitions];
 
        if (p && p->sys_ind) {
                printf(msg_part_already_defined, n + 1);
@@ -2222,12 +2200,9 @@ add_partition(int n, int sys)
        if (n < 4) {
                start = sector_offset;
                if (display_in_cyl_units || !total_number_of_sectors)
-                       llimit = heads * sectors * cylinders - 1;
+                       limit = (ullong) heads * sectors * cylinders - 1;
                else
-                       llimit = total_number_of_sectors - 1;
-               limit = llimit;
-               if (limit != llimit)
-                       limit = 0x7fffffff;
+                       limit = total_number_of_sectors - 1;
                if (extended_offset) {
                        first[ext_index] = extended_offset;
                        last[ext_index] = get_start_sect(q) +
@@ -2256,12 +2231,12 @@ add_partition(int n, int sys)
                if (start > limit)
                        break;
                if (start >= temp+units_per_sector && num_read) {
-                       printf("Sector %"OFF_FMT"d is already allocated\n", temp);
+                       printf("Sector %lld is already allocated\n", temp);
                        temp = start;
                        num_read = 0;
                }
                if (!num_read && start == temp) {
-                       off_t saved_start;
+                       ullong saved_start;
 
                        saved_start = start;
                        start = read_int(cround(saved_start), cround(saved_start), cround(limit),
@@ -2534,7 +2509,7 @@ move_begin(int i)
 {
        struct pte *pe = &ptes[i];
        struct partition *p = pe->part_table;
-       off_t new, first;
+       ullong new, first;
 
        if (warn_geometry())
                return;