From: Davidlohr Bueso <dave@xxxxxxx> Add device geometry to the fdisk API. While it maintains traditional behaviour, the cylinders are changed to sector_t instead of unsigned int in order to avoid dealing with truncated cylinders. A new helper is added to compute the amount of cylinders based on the heads and sectors - if a user passed -H or -S to the program, it must call this function to update the corresponding values. This patch passes regression tests. Signed-off-by: Davidlohr Bueso <dave@xxxxxxx> --- I've left get_partition_table_geometry() as the first choice for geometry discovery - this is very DOS. What about removing this call and only relying on what the bios/kernel says? fdisk/fdisk.c | 185 +++++++++++++++++++++--------------------------- fdisk/fdisk.h | 26 +++++--- fdisk/fdiskaixlabel.c | 2 +- fdisk/fdiskbsdlabel.c | 14 ++-- fdisk/fdiskdoslabel.c | 24 +++--- fdisk/fdiskmaclabel.c | 2 +- fdisk/fdisksgilabel.c | 42 ++++++------ fdisk/fdisksunlabel.c | 90 ++++++++++++------------ fdisk/utils.c | 37 ++++++++++ 9 files changed, 221 insertions(+), 201 deletions(-) diff --git a/fdisk/fdisk.c b/fdisk/fdisk.c index 6f9e412..5393d7e 100644 --- a/fdisk/fdisk.c +++ b/fdisk/fdisk.c @@ -135,15 +135,8 @@ int nowarn = 0, /* no warnings for fdisk -l/-s */ partitions = 4; /* maximum partition + 1 */ unsigned int user_cylinders, user_heads, user_sectors; -unsigned int pt_heads, pt_sectors; - -sector_t sector_offset = 1, sectors; - -unsigned int heads, - cylinders, - units_per_sector = 1, - display_in_cyl_units = 0; - +sector_t sector_offset = 1; +unsigned int units_per_sector = 1, display_in_cyl_units = 0; unsigned long grain = DEFAULT_SECTOR_SIZE; enum labeltype disklabel; /* Current disklabel */ @@ -365,18 +358,18 @@ sector_t align_lba(struct fdisk_context *cxt, sector_t lba, int direction) return res; } -int warn_geometry(void) +int warn_geometry(struct fdisk_context *cxt) { char *m = NULL; int prev = 0; if (disklabel == SGI_LABEL) /* cannot set cylinders etc anyway */ return 0; - if (!heads) + if (!cxt->geom.heads) prev = test_c(&m, _("heads")); - if (!sectors) + if (!cxt->geom.sectors) prev = test_c(&m, _("sectors")); - if (!cylinders) + if (!cxt->geom.cylinders) prev = test_c(&m, _("cylinders")); if (!m) return 0; @@ -386,9 +379,9 @@ int warn_geometry(void) return 1; } -void update_units(void) +void update_units(struct fdisk_context *cxt) { - int cyl_units = heads * sectors; + int cyl_units = cxt->geom.heads * cxt->geom.sectors; if (display_in_cyl_units && cyl_units) units_per_sector = cyl_units; @@ -438,8 +431,8 @@ void warn_alignment(struct fdisk_context *cxt) } -static void -get_partition_table_geometry(struct fdisk_context *cxt) { +void +get_partition_table_geometry(struct fdisk_context *cxt, unsigned int *ph, unsigned int *ps) { unsigned char *bufp = cxt->mbr; struct partition *p; int i, h, s, hh, ss; @@ -465,8 +458,8 @@ get_partition_table_geometry(struct fdisk_context *cxt) { } if (!first && !bad) { - pt_heads = hh; - pt_sectors = ss; + *ph = hh; + *ps = ss; } } @@ -479,7 +472,7 @@ update_sector_offset(struct fdisk_context *cxt) grain = cxt->io_size; if (dos_compatible_flag) - sector_offset = sectors; /* usually 63 sectors */ + sector_offset = cxt->geom.sectors; /* usually 63 sectors */ else { /* * Align the begin of partitions to: @@ -520,41 +513,6 @@ update_sector_offset(struct fdisk_context *cxt) } } -void -get_geometry(struct fdisk_context *cxt, struct geom *g) -{ - sector_t llcyls; - unsigned int kern_heads = 0, kern_sectors = 0; - - heads = cylinders = sectors = 0; - pt_heads = pt_sectors = 0; - - blkdev_get_geometry(cxt->dev_fd, &kern_heads, &kern_sectors); - get_partition_table_geometry(cxt); - - heads = user_heads ? user_heads : - pt_heads ? pt_heads : - kern_heads ? kern_heads : 255; - sectors = user_sectors ? user_sectors : - pt_sectors ? pt_sectors : - kern_sectors ? kern_sectors : 63; - - update_sector_offset(cxt); - - llcyls = cxt->total_sectors / (heads * sectors); - cylinders = llcyls; - if (cylinders != llcyls) /* truncated? */ - cylinders = ~0; - if (!cylinders) - cylinders = user_cylinders; - - if (g) { - g->heads = heads; - g->sectors = sectors; - g->cylinders = cylinders; - } -} - /* * Read MBR. Returns: * -1: no 0xaa55 flag present (possibly entire disk BSD) @@ -564,9 +522,7 @@ get_geometry(struct fdisk_context *cxt, struct geom *g) static int get_boot(struct fdisk_context *cxt, int try_only) { disklabel = ANY_LABEL; - - get_geometry(cxt, NULL); - update_units(); + update_units(cxt); if (!check_dos_label(cxt)) if (check_sun_label(cxt) || check_sgi_label(cxt) || check_aix_label(cxt) @@ -752,7 +708,7 @@ read_int_with_suffix(struct fdisk_context *cxt, * Cylinders */ if (!display_in_cyl_units) - res *= heads * sectors; + res *= cxt->geom.heads * cxt->geom.sectors; } else if (*line_ptr && *(line_ptr + 1) == 'B' && *(line_ptr + 2) == '\0') { @@ -907,10 +863,10 @@ str_units(int n) return P_("sector", "sectors", n); } -void change_units(void) +void change_units(struct fdisk_context *cxt) { display_in_cyl_units = !display_in_cyl_units; - update_units(); + update_units(cxt); if (display_in_cyl_units) printf(_("Changing display/entry units to cylinders (DEPRECATED!)\n")); @@ -948,7 +904,7 @@ delete_partition(struct fdisk_context *cxt, int i) if (i < 0) return; - if (warn_geometry()) + if (warn_geometry(cxt)) return; /* C/H/S not set */ ptes[i].changed = 1; @@ -1044,16 +1000,17 @@ static void change_sysid(struct fdisk_context *cxt) * Lubkin Oct. 1991). */ static void -long2chs(unsigned long ls, unsigned int *c, unsigned int *h, unsigned int *s) { - int spc = heads * sectors; +long2chs(struct fdisk_context *cxt, unsigned long ls, + unsigned int *c, unsigned int *h, unsigned int *s) { + int spc = cxt->geom.heads * cxt->geom.sectors; *c = ls / spc; ls = ls % spc; - *h = ls / sectors; - *s = ls % sectors + 1; /* sectors count from 1 */ + *h = ls / cxt->geom.sectors; + *s = ls % cxt->geom.sectors + 1; /* sectors count from 1 */ } -static void check_consistency(struct partition *p, int partition) { +static void check_consistency(struct fdisk_context *cxt, struct partition *p, int partition) { unsigned int pbc, pbh, pbs; /* physical beginning c, h, s */ unsigned int pec, peh, pes; /* physical ending c, h, s */ unsigned int lbc, lbh, lbs; /* logical beginning c, h, s */ @@ -1062,7 +1019,7 @@ static void check_consistency(struct partition *p, int partition) { if (!dos_compatible_flag) return; - if (!heads || !sectors || (partition >= 4)) + if (!cxt->geom.heads || !cxt->geom.sectors || (partition >= 4)) return; /* do not check extended partitions */ /* physical beginning c, h, s */ @@ -1076,13 +1033,13 @@ static void check_consistency(struct partition *p, int partition) { pes = p->end_sector & 0x3f; /* compute logical beginning (c, h, s) */ - long2chs(get_start_sect(p), &lbc, &lbh, &lbs); + long2chs(cxt, get_start_sect(p), &lbc, &lbh, &lbs); /* compute logical ending (c, h, s) */ - long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les); + long2chs(cxt, get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les); /* Same physical / logical beginning? */ - if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) { + if (cxt->geom.cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) { printf(_("Partition %d has different physical/logical " "beginnings (non-Linux?):\n"), partition + 1); printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs); @@ -1090,7 +1047,7 @@ static void check_consistency(struct partition *p, int partition) { } /* Same physical / logical ending? */ - if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) { + if (cxt->geom.cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) { printf(_("Partition %d has different physical/logical " "endings:\n"), partition + 1); printf(_(" phys=(%d, %d, %d) "), pec, peh, pes); @@ -1098,7 +1055,7 @@ static void check_consistency(struct partition *p, int partition) { } /* Ending on cylinder boundary? */ - if (peh != (heads - 1) || pes != sectors) { + if (peh != (cxt->geom.heads - 1) || pes != cxt->geom.sectors) { printf(_("Partition %i does not end on cylinder boundary.\n"), partition + 1); } @@ -1125,8 +1082,8 @@ list_disk_geometry(struct fdisk_context *cxt) { printf(_("\nDisk %s: %ld.%ld GB, %llu bytes\n"), cxt->dev_path, hectomega / 10, hectomega % 10, bytes); } - printf(_("%d heads, %llu sectors/track, %d cylinders"), - heads, sectors, cylinders); + printf(_("%d heads, %llu sectors/track, %llu cylinders"), + cxt->geom.heads, cxt->geom.sectors, cxt->geom.cylinders); if (units_per_sector == 1) printf(_(", total %llu sectors"), cxt->total_sectors); printf("\n"); @@ -1347,7 +1304,7 @@ list_table(struct fdisk_context *cxt, int xtra) { /* type id */ p->sys_ind, /* type name */ (type = partition_type(p->sys_ind)) ? type : _("Unknown")); - check_consistency(p, i); + check_consistency(cxt, p, i); check_alignment(cxt, get_partition_start(pe), i); } } @@ -1366,8 +1323,8 @@ x_list_table(struct fdisk_context *cxt, int extend) { struct partition *p; int i; - printf(_("\nDisk %s: %d heads, %llu sectors, %d cylinders\n\n"), - cxt->dev_path, heads, sectors, cylinders); + printf(_("\nDisk %s: %d heads, %llu sectors, %llu cylinders\n\n"), + cxt->dev_path, cxt->geom.heads, cxt->geom.sectors, cxt->geom.cylinders); printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n")); for (i = 0 ; i < partitions; i++) { pe = &ptes[i]; @@ -1382,7 +1339,7 @@ x_list_table(struct fdisk_context *cxt, int extend) { (unsigned long) get_start_sect(p), (unsigned long) get_nr_sects(p), p->sys_ind); if (p->sys_ind) { - check_consistency(p, i); + check_consistency(cxt, p, i); check_alignment(cxt, get_partition_start(pe), i); } } @@ -1408,26 +1365,26 @@ void fill_bounds(sector_t *first, sector_t *last) } static void -check(int n, unsigned int h, unsigned int s, unsigned int c, +check(struct fdisk_context *cxt, int n, unsigned int h, unsigned int s, unsigned int c, unsigned int start) { unsigned int total, real_s, real_c; real_s = sector(s) - 1; real_c = cylinder(s, c); - total = (real_c * sectors + real_s) * heads + h; + total = (real_c * cxt->geom.sectors + real_s) * cxt->geom.heads + h; if (!total) fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n); - if (h >= heads) + if (h >= cxt->geom.heads) fprintf(stderr, _("Partition %d: head %d greater than maximum %d\n"), - n, h + 1, heads); - if (real_s >= sectors) + n, h + 1, cxt->geom.heads); + if (real_s >= cxt->geom.sectors) fprintf(stderr, _("Partition %d: sector %d greater than " - "maximum %llu\n"), n, s, sectors); - if (real_c >= cylinders) + "maximum %llu\n"), n, s, cxt->geom.sectors); + if (real_c >= cxt->geom.cylinders) fprintf(stderr, _("Partitions %d: cylinder %d greater than " - "maximum %d\n"), n, real_c + 1, cylinders); - if (cylinders <= 1024 && start != total) + "maximum %llu\n"), n, real_c + 1, cxt->geom.cylinders); + if (cxt->geom.cylinders <= 1024 && start != total) fprintf(stderr, _("Partition %d: previous sectors %d disagrees with " "total %d\n"), n, start, total); @@ -1440,7 +1397,7 @@ verify(struct fdisk_context *cxt) { unsigned long long first[partitions], last[partitions]; struct partition *p; - if (warn_geometry()) + if (warn_geometry(cxt)) return; if (disklabel == SUN_LABEL) { @@ -1459,13 +1416,13 @@ verify(struct fdisk_context *cxt) { p = pe->part_table; if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) { - check_consistency(p, i); + check_consistency(cxt, p, i); check_alignment(cxt, get_partition_start(pe), i); if (get_partition_start(pe) < first[i]) printf(_("Warning: bad start-of-data in " "partition %d\n"), i + 1); - check(i + 1, p->end_head, p->end_sector, p->end_cyl, - last[i]); + check(cxt, i + 1, p->end_head, p->end_sector, p->end_cyl, + last[i]); total += last[i] + 1 - first[i]; for (j = 0; j < i; j++) if ((first[i] >= first[j] && first[i] <= last[j]) @@ -1519,7 +1476,7 @@ void print_partition_size(struct fdisk_context *cxt, static void new_partition(struct fdisk_context *cxt) { - if (warn_geometry()) + if (warn_geometry(cxt)) return; if (disklabel == SUN_LABEL) { @@ -1656,7 +1613,7 @@ move_begin(struct fdisk_context *cxt, int i) { unsigned int new, free_start, curr_start, last; int x; - if (warn_geometry()) + if (warn_geometry(cxt)) return; if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED (p->sys_ind)) { printf(_("Partition %d has no data area\n"), i + 1); @@ -1723,11 +1680,11 @@ expert_command_prompt(struct fdisk_context *cxt) move_begin(cxt, get_partition(cxt, 0, partitions)); break; case 'c': - user_cylinders = cylinders = - read_int(cxt, 1, cylinders, 1048576, 0, + user_cylinders = cxt->geom.cylinders = + read_int(cxt, 1, cxt->geom.cylinders, 1048576, 0, _("Number of cylinders")); if (disklabel == SUN_LABEL) - sun_set_ncyl(cxt, cylinders); + sun_set_ncyl(cxt, cxt->geom.cylinders); break; case 'd': print_raw(cxt); @@ -1749,9 +1706,9 @@ expert_command_prompt(struct fdisk_context *cxt) create_sgilabel(cxt); break; case 'h': - user_heads = heads = read_int(cxt, 1, heads, 256, 0, + user_heads = cxt->geom.heads = read_int(cxt, 1, cxt->geom.heads, 256, 0, _("Number of heads")); - update_units(); + update_units(cxt); break; case 'i': if (disklabel == SUN_LABEL) @@ -1774,14 +1731,14 @@ expert_command_prompt(struct fdisk_context *cxt) case 'r': return; case 's': - user_sectors = sectors = read_int(cxt, 1, sectors, 63, 0, + user_sectors = cxt->geom.sectors = read_int(cxt, 1, cxt->geom.sectors, 63, 0, _("Number of sectors")); if (dos_compatible_flag) fprintf(stderr, _("Warning: setting " "sector offset for DOS " "compatiblity\n")); update_sector_offset(cxt); - update_units(); + update_units(cxt); break; case 'v': verify(cxt); @@ -1829,6 +1786,17 @@ static void print_partition_table_from_option(char *device, unsigned long sector err(EXIT_FAILURE, _("unable to open %s"), device); if (sector_size) /* passed -b option, override autodiscovery */ cxt->phy_sector_size = cxt->sector_size = sector_size; + /* passed CHS option(s), override autodiscovery */ + if (user_cylinders) + cxt->geom.cylinders = user_cylinders; + if (user_heads) { + cxt->geom.heads = user_heads; + fdisk_geom_set_cyls(cxt); + } + if (user_sectors) { + cxt->geom.sectors = user_sectors; + fdisk_geom_set_cyls(cxt); + } gpt_warning(device); gb = get_boot(cxt, 1); @@ -1978,7 +1946,7 @@ static void command_prompt(struct fdisk_context *cxt) change_sysid(cxt); break; case 'u': - change_units(); + change_units(cxt); break; case 'v': verify(cxt); @@ -2086,8 +2054,6 @@ int main(int argc, char **argv) printf(_("Warning: the -b (set sector size) option should" " be used with one specified device\n")); - /* init_mbr_buffer(); */ - if (optl) { nowarn = 1; if (argc > optind) { @@ -2120,6 +2086,17 @@ int main(int argc, char **argv) err(EXIT_FAILURE, _("unable to open %s"), argv[optind]); if (sector_size) /* passed -b option, override autodiscovery */ cxt->phy_sector_size = cxt->sector_size = sector_size; + /* passed CHS option(s), override autodiscovery */ + if (user_cylinders) + cxt->geom.cylinders = user_cylinders; + if (user_heads) { + cxt->geom.heads = user_heads; + fdisk_geom_set_cyls(cxt); + } + if (user_sectors) { + cxt->geom.sectors = user_sectors; + fdisk_geom_set_cyls(cxt); + } } else usage(stderr); diff --git a/fdisk/fdisk.h b/fdisk/fdisk.h index b4f2814..5b57953 100644 --- a/fdisk/fdisk.h +++ b/fdisk/fdisk.h @@ -36,6 +36,7 @@ #define FDISK_DEBUG_INIT (1 << 1) #define FDISK_DEBUG_CONTEXT (1 << 2) #define FDISK_DEBUG_TOPOLOGY (1 << 3) +#define FDISK_DEBUG_GEOMETRY (1 << 4) #define FDISK_DEBUG_ALL 0xFFFF # define ON_DBG(m, x) do { \ @@ -95,14 +96,17 @@ enum failure { unable_to_write }; -struct geom { +typedef unsigned long long sector_t; + +/* + * Legacy CHS based geometry + */ +struct fdisk_geometry { unsigned int heads; - unsigned int sectors; - unsigned int cylinders; + sector_t sectors; + sector_t cylinders; }; -typedef unsigned long long sector_t; - struct fdisk_context { int dev_fd; /* device descriptor */ char *dev_path; /* device path */ @@ -118,6 +122,7 @@ struct fdisk_context { /* geometry */ sector_t total_sectors; /* in logical sectors */ + struct fdisk_geometry geom; }; extern struct fdisk_context *fdisk_new_context_from_filename(const char *fname, int readonly); @@ -125,14 +130,14 @@ extern int fdisk_dev_has_topology(struct fdisk_context *cxt); extern int fdisk_dev_sectsz_is_default(struct fdisk_context *cxt); extern void fdisk_free_context(struct fdisk_context *cxt); extern void fdisk_mbr_zeroize(struct fdisk_context *cxt); +extern void fdisk_geom_set_cyls(struct fdisk_context *cxt); /* prototypes for fdisk.c */ extern char *disk_device, *line_ptr; extern int fd, partitions; extern unsigned int display_in_cyl_units, units_per_sector; -extern void change_units(void); +extern void change_units(struct fdisk_context *cxt); extern void fatal(struct fdisk_context *cxt, enum failure why); -extern void get_geometry(struct fdisk_context *, struct geom *); extern int get_partition(struct fdisk_context *cxt, int warn, int max); extern void list_types(struct systypes *sys); extern int read_line (int *asked); @@ -151,11 +156,11 @@ extern void fill_bounds(sector_t *first, sector_t *last); extern unsigned int heads, cylinders; extern sector_t sectors; extern char *partition_type(unsigned char type); -extern void update_units(void); +extern void update_units(struct fdisk_context *cxt); extern char read_chars(char *mesg); extern void set_changed(int); extern void set_all_unchanged(void); -extern int warn_geometry(void); +extern int warn_geometry(struct fdisk_context *cxt); extern void warn_limits(struct fdisk_context *cxt); extern void warn_alignment(struct fdisk_context *cxt); extern unsigned int read_int_with_suffix(struct fdisk_context *cxt, @@ -163,6 +168,9 @@ extern unsigned int read_int_with_suffix(struct fdisk_context *cxt, unsigned int base, char *mesg, int *is_suffix_used); extern sector_t align_lba(struct fdisk_context *cxt, sector_t lba, int direction); extern int get_partition_dflt(struct fdisk_context *cxt, int warn, int max, int dflt); +extern void update_sector_offset(struct fdisk_context *cxt); +extern void get_partition_table_geometry(struct fdisk_context *cxt, + unsigned int *ph, unsigned int *ps); #define PLURAL 0 #define SINGULAR 1 diff --git a/fdisk/fdiskaixlabel.c b/fdisk/fdiskaixlabel.c index c15ab74..fb36489 100644 --- a/fdisk/fdiskaixlabel.c +++ b/fdisk/fdiskaixlabel.c @@ -57,7 +57,7 @@ int check_aix_label(struct fdisk_context *cxt) return 0; } other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED); - update_units(); + update_units(cxt); disklabel = AIX_LABEL; partitions= 1016; volumes = 15; diff --git a/fdisk/fdiskbsdlabel.c b/fdisk/fdiskbsdlabel.c index b92530f..dc14581 100644 --- a/fdisk/fdiskbsdlabel.c +++ b/fdisk/fdiskbsdlabel.c @@ -213,7 +213,7 @@ bsd_command_prompt (struct fdisk_context *cxt) xbsd_change_fstype (); break; case 'u': - change_units(); + change_units(cxt); break; case 'w': xbsd_write_disklabel (cxt); @@ -636,9 +636,7 @@ static int xbsd_initlabel (struct fdisk_context *cxt, struct partition *p, struct xbsd_disklabel *d, int pindex __attribute__((__unused__))) { struct xbsd_partition *pp; - struct geom g; - - get_geometry (cxt, &g); + memset (d, 0, sizeof (struct xbsd_disklabel)); d -> d_magic = BSD_DISKMAGIC; @@ -658,10 +656,10 @@ xbsd_initlabel (struct fdisk_context *cxt, struct partition *p, struct xbsd_disk d -> d_flags = 0; #endif d -> d_secsize = SECTOR_SIZE; /* bytes/sector */ - d -> d_nsectors = g.sectors; /* sectors/track */ - d -> d_ntracks = g.heads; /* tracks/cylinder (heads) */ - d -> d_ncylinders = g.cylinders; - d -> d_secpercyl = g.sectors * g.heads;/* sectors/cylinder */ + d -> d_nsectors = cxt->geom.sectors; /* sectors/track */ + d -> d_ntracks = cxt->geom.heads; /* tracks/cylinder (heads) */ + d -> d_ncylinders = cxt->geom.cylinders; + d -> d_secpercyl = cxt->geom.sectors * cxt->geom.heads;/* sectors/cylinder */ if (d -> d_secpercyl == 0) d -> d_secpercyl = 1; /* avoid segfaults */ d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders; diff --git a/fdisk/fdiskdoslabel.c b/fdisk/fdiskdoslabel.c index abf101b..a72a432 100644 --- a/fdisk/fdiskdoslabel.c +++ b/fdisk/fdiskdoslabel.c @@ -14,12 +14,12 @@ #include "fdiskdoslabel.h" #define set_hsc(h,s,c,sector) { \ - s = sector % sectors + 1; \ - sector /= sectors; \ - h = sector % heads; \ - sector /= heads; \ - c = sector & 0xff; \ - s |= (sector >> 2) & 0xc0; \ + s = sector % cxt->geom.sectors + 1; \ + sector /= cxt->geom.sectors; \ + h = sector % cxt->geom.heads; \ + sector /= cxt->geom.heads; \ + c = sector & 0xff; \ + s |= (sector >> 2) & 0xc0; \ } #define alignment_required (grain != cxt->sector_size) @@ -115,7 +115,7 @@ void dos_init(struct fdisk_context *cxt) pe->changed = 0; } - warn_geometry(); + warn_geometry(cxt); warn_limits(cxt); warn_alignment(cxt); } @@ -389,11 +389,11 @@ static void set_partition(struct fdisk_context *cxt, if (!doext) print_partition_size(cxt, i + 1, start, stop, sysid); - if (dos_compatible_flag && (start/(sectors*heads) > 1023)) - start = heads*sectors*1024 - 1; + if (dos_compatible_flag && (start/(cxt->geom.sectors*cxt->geom.heads) > 1023)) + start = cxt->geom.heads*cxt->geom.sectors*1024 - 1; set_hsc(p->head, p->sector, p->cyl, start); - if (dos_compatible_flag && (stop/(sectors*heads) > 1023)) - stop = heads*sectors*1024 - 1; + if (dos_compatible_flag && (stop/(cxt->geom.sectors*cxt->geom.heads) > 1023)) + stop = cxt->geom.heads*cxt->geom.sectors*1024 - 1; set_hsc(p->end_head, p->end_sector, p->end_cyl, stop); ptes[i].changed = 1; } @@ -449,7 +449,7 @@ void dos_add_partition(struct fdisk_context *cxt, int n, int sys) if (n < 4) { start = sector_offset; if (display_in_cyl_units || !cxt->total_sectors) - limit = heads * sectors * cylinders - 1; + limit = cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders - 1; else limit = cxt->total_sectors - 1; diff --git a/fdisk/fdiskmaclabel.c b/fdisk/fdiskmaclabel.c index 1c2e403..96fc712 100644 --- a/fdisk/fdiskmaclabel.c +++ b/fdisk/fdiskmaclabel.c @@ -72,7 +72,7 @@ check_mac_label(struct fdisk_context *cxt) IS_MAC: other_endian = (maclabel->magic == MAC_LABEL_MAGIC_SWAPPED); // =? - update_units(); + update_units(cxt); disklabel = MAC_LABEL; partitions= 1016; // =? volumes = 15; // =? diff --git a/fdisk/fdisksgilabel.c b/fdisk/fdisksgilabel.c index b7c1db2..c723403 100644 --- a/fdisk/fdisksgilabel.c +++ b/fdisk/fdisksgilabel.c @@ -151,7 +151,7 @@ check_sgi_label(struct fdisk_context *cxt) { fprintf(stderr, _("Detected sgi disklabel with wrong checksum.\n")); } - update_units(); + update_units(cxt); disklabel = SGI_LABEL; partitions= 16; volumes = 15; @@ -168,11 +168,11 @@ sgi_list_table(struct fdisk_context *cxt, int xtra) { if (xtra) { printf(_("\nDisk %s (SGI disk label): %d heads, %llu sectors\n" - "%d cylinders, %d physical cylinders\n" + "%llu cylinders, %d physical cylinders\n" "%d extra sects/cyl, interleave %d:1\n" "%s\n" "Units = %s of %d * %ld bytes\n\n"), - cxt->dev_path, heads, sectors, cylinders, + cxt->dev_path, cxt->geom.heads, cxt->geom.sectors, cxt->geom.cylinders, SSWAP16(sgiparam.pcylcount), (int) sgiparam.sparecyl, SSWAP16(sgiparam.ilfact), (char *)sgilabel, @@ -180,9 +180,9 @@ sgi_list_table(struct fdisk_context *cxt, int xtra) { cxt->sector_size); } else { printf(_("\nDisk %s (SGI disk label): " - "%d heads, %llu sectors, %d cylinders\n" + "%d heads, %llu sectors, %llu cylinders\n" "Units = %s of %d * %ld bytes\n\n"), - cxt->dev_path, heads, sectors, cylinders, + cxt->dev_path, cxt->geom.heads, cxt->geom.sectors, cxt->geom.cylinders, str_units(PLURAL), units_per_sector, cxt->sector_size); } @@ -258,8 +258,8 @@ sgi_set_bootpartition(struct fdisk_context *cxt, int i) } static unsigned int -sgi_get_lastblock(void) { - return heads * sectors * cylinders; +sgi_get_lastblock(struct fdisk_context *cxt) { + return cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders; } void @@ -445,7 +445,7 @@ verify_sgi(struct fdisk_context *cxt, int verbose) int entire = 0, i = 0; unsigned int start = 0; long long gap = 0; /* count unused blocks */ - unsigned int lastblock = sgi_get_lastblock(); + unsigned int lastblock = sgi_get_lastblock(cxt); clearfreelist(); for (i=0; i<16; i++) { @@ -613,7 +613,7 @@ sgi_set_entire(struct fdisk_context *cxt) { for (n=10; n<partitions; n++) { if (!sgi_get_num_sectors(cxt, n)) { - sgi_set_partition(cxt, n, 0, sgi_get_lastblock(), SGI_VOLUME); + sgi_set_partition(cxt, n, 0, sgi_get_lastblock(cxt), SGI_VOLUME); break; } } @@ -631,7 +631,7 @@ sgi_set_volhdr(struct fdisk_context *cxt) * Choose same default volume header size * as IRIX fx uses. */ - if (4096 < sgi_get_lastblock()) + if (4096 < sgi_get_lastblock(cxt)) sgi_set_partition(cxt, n, 0, 4096, SGI_VOLHDR); break; } @@ -677,7 +677,7 @@ sgi_add_partition(struct fdisk_context *cxt, int n, int sys) snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR)); for (;;) { if (sys == SGI_VOLUME) { - last = sgi_get_lastblock(); + last = sgi_get_lastblock(cxt); first = read_int(cxt, 0, 0, last-1, 0, mesg); if (first != 0) { printf(_("It is highly recommended that eleventh partition\n" @@ -708,7 +708,7 @@ sgi_add_partition(struct fdisk_context *cxt, int n, int sys) last *= units_per_sector; /*else last = last; * align to cylinder if You know how ... */ - if ((sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock())) + if ((sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock(cxt))) printf(_("It is highly recommended that eleventh partition\n" "covers the entire disk and is of type `SGI volume'\n")); sgi_set_partition(cxt, n, first, last-first, sys); @@ -741,23 +741,23 @@ create_sgilabel(struct fdisk_context *cxt) if (ioctl(cxt->dev_fd, HDIO_GETGEO, &geometry) < 0) err(EXIT_FAILURE, _("HDIO_GETGEO ioctl failed on %s"), cxt->dev_path); - heads = geometry.heads; - sectors = geometry.sectors; + cxt->geom.heads = geometry.heads; + cxt->geom.sectors = geometry.sectors; if (res == 0) { /* the get device size ioctl was successful */ sector_t llcyls; - llcyls = llsectors / (heads * sectors * sec_fac); - cylinders = llcyls; - if (cylinders != llcyls) /* truncated? */ - cylinders = ~0; + llcyls = llsectors / (cxt->geom.heads * cxt->geom.sectors * sec_fac); + cxt->geom.cylinders = llcyls; + if (cxt->geom.cylinders != llcyls) /* truncated? */ + cxt->geom.cylinders = ~0; } else { /* otherwise print error and use truncated version */ - cylinders = geometry.cylinders; + cxt->geom.cylinders = geometry.cylinders; fprintf(stderr, _("Warning: BLKGETSIZE ioctl failed on %s. " - "Using geometry cylinder value of %d.\n" + "Using geometry cylinder value of %llu.\n" "This value may be truncated for devices" - " > 33.8 GB.\n"), cxt->dev_path, cylinders); + " > 33.8 GB.\n"), cxt->dev_path, cxt->geom.cylinders); } #endif for (i = 0; i < 4; i++) { diff --git a/fdisk/fdisksunlabel.c b/fdisk/fdisksunlabel.c index 5dbcef4..ecfaa1e 100644 --- a/fdisk/fdisksunlabel.c +++ b/fdisk/fdisksunlabel.c @@ -65,7 +65,7 @@ static void set_sun_partition(struct fdisk_context *cxt, sunlabel->part_tags[i].tag = SSWAP16(sysid); sunlabel->part_tags[i].flag = SSWAP16(0); sunlabel->partitions[i].start_cylinder = - SSWAP32(start / (heads * sectors)); + SSWAP32(start / (cxt->geom.heads * cxt->geom.sectors)); sunlabel->partitions[i].num_sectors = SSWAP32(stop - start); set_changed(i); @@ -104,9 +104,9 @@ int check_sun_label(struct fdisk_context *cxt) } else { int need_fixing = 0; - heads = SSWAP16(sunlabel->nhead); - cylinders = SSWAP16(sunlabel->ncyl); - sectors = SSWAP16(sunlabel->nsect); + cxt->geom.heads = SSWAP16(sunlabel->nhead); + cxt->geom.cylinders = SSWAP16(sunlabel->ncyl); + cxt->geom.sectors = SSWAP16(sunlabel->nsect); if (sunlabel->version != SSWAP32(SUN_LABEL_VERSION)) { fprintf(stderr,_("Detected sun disklabel with wrong version [0x%08x].\n"), @@ -140,7 +140,7 @@ int check_sun_label(struct fdisk_context *cxt) set_changed(0); } } - update_units(); + update_units(cxt); return 1; } @@ -172,57 +172,57 @@ void create_sunlabel(struct fdisk_context *cxt) #ifdef HDIO_GETGEO if (!ioctl(cxt->dev_fd, HDIO_GETGEO, &geometry)) { - heads = geometry.heads; - sectors = geometry.sectors; + cxt->geom.heads = geometry.heads; + cxt->geom.sectors = geometry.sectors; if (res == 0) { - llcyls = llsectors / (heads * sectors * sec_fac); - cylinders = llcyls; - if (cylinders != llcyls) - cylinders = ~0; + llcyls = llsectors / (cxt->geom.heads * cxt->geom.sectors * sec_fac); + cxt->geom.cylinders = llcyls; + if (cxt->geom.cylinders != llcyls) + cxt->geom.cylinders = ~0; } else { - cylinders = geometry.cylinders; + cxt->geom.cylinders = geometry.cylinders; fprintf(stderr, _("Warning: BLKGETSIZE ioctl failed on %s. " - "Using geometry cylinder value of %d.\n" + "Using geometry cylinder value of %llu.\n" "This value may be truncated for devices" - " > 33.8 GB.\n"), cxt->dev_path, cylinders); + " > 33.8 GB.\n"), cxt->dev_path, cxt->geom.cylinders); } } else #endif { - heads = read_int(cxt, 1,1,1024,0,_("Heads")); - sectors = read_int(cxt, 1,1,1024,0,_("Sectors/track")); - cylinders = read_int(cxt, 1,1,65535,0,_("Cylinders")); + cxt->geom.heads = read_int(cxt, 1,1,1024,0,_("Heads")); + cxt->geom.sectors = read_int(cxt, 1,1,1024,0,_("Sectors/track")); + cxt->geom.cylinders = read_int(cxt, 1,1,65535,0,_("Cylinders")); } sunlabel->acyl = SSWAP16(2); - sunlabel->pcyl = SSWAP16(cylinders); - sunlabel->ncyl = SSWAP16(cylinders - 2); + sunlabel->pcyl = SSWAP16(cxt->geom.cylinders); + sunlabel->ncyl = SSWAP16(cxt->geom.cylinders - 2); sunlabel->rpm = SSWAP16(5400); sunlabel->intrlv = SSWAP16(1); sunlabel->apc = SSWAP16(0); - sunlabel->nhead = SSWAP16(heads); - sunlabel->nsect = SSWAP16(sectors); - sunlabel->ncyl = SSWAP16(cylinders); + sunlabel->nhead = SSWAP16(cxt->geom.heads); + sunlabel->nsect = SSWAP16(cxt->geom.sectors); + sunlabel->ncyl = SSWAP16(cxt->geom.cylinders); snprintf(sunlabel->label_id, sizeof(sunlabel->label_id), - "Linux cyl %d alt %d hd %d sec %llu", - cylinders, SSWAP16(sunlabel->acyl), heads, sectors); + "Linux cyl %llu alt %d hd %d sec %llu", + cxt->geom.cylinders, SSWAP16(sunlabel->acyl), cxt->geom.heads, cxt->geom.sectors); - if (cylinders * heads * sectors >= 150 * 2048) { - ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */ + if (cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors >= 150 * 2048) { + ndiv = cxt->geom.cylinders - (50 * 2048 / (cxt->geom.heads * cxt->geom.sectors)); /* 50M swap */ } else - ndiv = cylinders * 2 / 3; + ndiv = cxt->geom.cylinders * 2 / 3; - set_sun_partition(cxt, 0, 0, ndiv * heads * sectors, + set_sun_partition(cxt, 0, 0, ndiv * cxt->geom.heads * cxt->geom.sectors, SUN_TAG_LINUX_NATIVE); - set_sun_partition(cxt, 1, ndiv * heads * sectors, - cylinders * heads * sectors, + set_sun_partition(cxt, 1, ndiv * cxt->geom.heads * cxt->geom.sectors, + cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors, SUN_TAG_LINUX_SWAP); sunlabel->part_tags[1].flag |= SSWAP16(SUN_FLAG_UNMNT); - set_sun_partition(cxt, 2, 0, cylinders * heads * sectors, SUN_TAG_BACKUP); + set_sun_partition(cxt, 2, 0, cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors, SUN_TAG_BACKUP); { unsigned short *ush = (unsigned short *)sunlabel; @@ -251,7 +251,7 @@ static void fetch_sun(struct fdisk_context *cxt, uint32_t *starts, int i, continuous = 1; *start = 0; - *stop = cylinders * heads * sectors; + *stop = cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors; for (i = 0; i < partitions; i++) { struct sun_partition *part = &sunlabel->partitions[i]; @@ -261,7 +261,7 @@ static void fetch_sun(struct fdisk_context *cxt, uint32_t *starts, tag->tag != SSWAP16(SUN_TAG_UNASSIGNED) && tag->tag != SSWAP16(SUN_TAG_BACKUP)) { starts[i] = (SSWAP32(part->start_cylinder) * - heads * sectors); + cxt->geom.heads * cxt->geom.sectors); lens[i] = SSWAP32(part->num_sectors); if (continuous) { if (starts[i] == *start) @@ -305,7 +305,7 @@ void verify_sun(struct fdisk_context *cxt) for (k = 0; k < 7; k++) { for (i = 0; i < SUN_NUM_PARTITIONS; i++) { - if (k && (lens[i] % (heads * sectors))) { + if (k && (lens[i] % (cxt->geom.heads * cxt->geom.sectors))) { printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1); } if (lens[i]) { @@ -347,7 +347,7 @@ void verify_sun(struct fdisk_context *cxt) printf(_("No partitions defined\n")); return; } - stop = cylinders * heads * sectors; + stop = cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors; if (starts[array[0]]) printf(_("Unused gap - sectors 0-%d\n"), starts[array[0]]); for (i = 0; i < 7 && array[i+1] != -1; i++) { @@ -399,7 +399,7 @@ void add_sun_partition(struct fdisk_context *cxt, int n, int sys) first *= units_per_sector; else { /* Starting sector has to be properly aligned */ - int cs = heads * sectors; + int cs = cxt->geom.heads * cxt->geom.sectors; int x = first % cs; if (x) @@ -438,7 +438,7 @@ and is of type `Whole disk'\n")); } else break; } - stop = cylinders * heads * sectors; /* ancient */ + stop = cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors; /* ancient */ stop2 = stop; for (i = 0; i < partitions; i++) { if (starts[i] > first && starts[i] < stop) @@ -490,7 +490,7 @@ void sun_delete_partition(struct fdisk_context *cxt, int i) tag->tag == SSWAP16(SUN_TAG_BACKUP) && !part->start_cylinder && (nsec = SSWAP32(part->num_sectors)) - == heads * sectors * cylinders) + == cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders) printf(_("If you want to maintain SunOS/Solaris compatibility, " "consider leaving this\n" "partition as Whole disk (5), starting at 0, with %u " @@ -539,13 +539,13 @@ void sun_list_table(struct fdisk_context *cxt, int xtra) if (xtra) printf( _("\nDisk %s (Sun disk label): %u heads, %llu sectors, %d rpm\n" - "%u cylinders, %d alternate cylinders, %d physical cylinders\n" + "%llu cylinders, %d alternate cylinders, %d physical cylinders\n" "%d extra sects/cyl, interleave %d:1\n" "Label ID: %s\n" "Volume ID: %s\n" "Units = %s of %d * 512 bytes\n\n"), - cxt->dev_path, heads, sectors, SSWAP16(sunlabel->rpm), - cylinders, SSWAP16(sunlabel->acyl), + cxt->dev_path, cxt->geom.heads, cxt->geom.sectors, SSWAP16(sunlabel->rpm), + cxt->geom.cylinders, SSWAP16(sunlabel->acyl), SSWAP16(sunlabel->pcyl), SSWAP16(sunlabel->apc), SSWAP16(sunlabel->intrlv), @@ -554,9 +554,9 @@ void sun_list_table(struct fdisk_context *cxt, int xtra) str_units(PLURAL), units_per_sector); else printf( - _("\nDisk %s (Sun disk label): %u heads, %llu sectors, %u cylinders\n" + _("\nDisk %s (Sun disk label): %u heads, %llu sectors, %llu cylinders\n" "Units = %s of %d * 512 bytes\n\n"), - cxt->dev_path, heads, sectors, cylinders, + cxt->dev_path, cxt->geom.heads, cxt->geom.sectors, cxt->geom.cylinders, str_units(PLURAL), units_per_sector); printf(_("%*s Flag Start End Blocks Id System\n"), @@ -566,7 +566,7 @@ void sun_list_table(struct fdisk_context *cxt, int xtra) struct sun_tag_flag *tag = &sunlabel->part_tags[i]; if (part->num_sectors) { - uint32_t start = SSWAP32(part->start_cylinder) * heads * sectors; + uint32_t start = SSWAP32(part->start_cylinder) * cxt->geom.heads * cxt->geom.sectors; uint32_t len = SSWAP32(part->num_sectors); printf( "%s %c%c %9lu %9lu %9lu%c %2x %s\n", @@ -598,7 +598,7 @@ void sun_set_ncyl(struct fdisk_context *cxt, int cyl) void sun_set_xcyl(struct fdisk_context *cxt) { sunlabel->apc = - SSWAP16(read_int(cxt, 0, SSWAP16(sunlabel->apc), sectors, 0, + SSWAP16(read_int(cxt, 0, SSWAP16(sunlabel->apc), cxt->geom.sectors, 0, _("Extra sectors per cylinder"))); } diff --git a/fdisk/utils.c b/fdisk/utils.c index 616fcc0..57f3355 100644 --- a/fdisk/utils.c +++ b/fdisk/utils.c @@ -55,13 +55,50 @@ static unsigned long __get_sector_size(int fd) return DEFAULT_SECTOR_SIZE; } +/** + * fdisk_geom_set_cyls + * @cxt: fdisk context + * + * Sets the cylinders based on sectors and heads + */ +void fdisk_geom_set_cyls(struct fdisk_context *cxt) +{ + cxt->geom.cylinders = cxt->total_sectors / + (cxt->geom.heads * cxt->geom.sectors); +} + static int __discover_geometry(struct fdisk_context *cxt) { sector_t nsects; + unsigned int h = 0, s = 0; /* get number of 512-byte sectors, and convert it the real sectors */ if (!blkdev_get_sectors(cxt->dev_fd, &nsects)) cxt->total_sectors = (nsects / (cxt->sector_size >> 9)); + + get_partition_table_geometry(cxt, &h, &s); + if (h && s) + goto hs_ok; + + /* what the kernel/bios thinks the geometry is */ + blkdev_get_geometry(cxt->dev_fd, &h, &s); + if (h && s) + goto hs_ok; + + /* unable to discover geometry, use default values */ + s = 63; + h = 255; + +hs_ok: /* obtained heads and sectors */ + cxt->geom.heads = h; + cxt->geom.sectors = s; + fdisk_geom_set_cyls(cxt); + update_sector_offset(cxt); + + DBG(GEOMETRY, dbgprint("geometry discovered for %s: C/H/S: %lld/%d/%lld", + cxt->dev_path, cxt->geom.cylinders, + cxt->geom.heads, cxt->geom.sectors)); + return 0; } -- 1.7.4.1 -- To unsubscribe from this list: send the line "unsubscribe util-linux" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html