fdisk: make it work with big disks (read: typical today's disks)

even if CONFIG_LFS is unset.
This commit is contained in:
Denis Vlasenko
2007-06-02 12:46:55 +00:00
parent a0d7508748
commit 3f22b7f718

View File

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