diff options
Diffstat (limited to 'util-linux/fdisk.c')
-rw-r--r-- | util-linux/fdisk.c | 227 |
1 files changed, 103 insertions, 124 deletions
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index dcfae96..57d4d65 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c @@ -78,13 +78,13 @@ static const char ioctl_error[] ALIGN1 = "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 + LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF }; -#define LABEL_IS_DOS (label_dos == current_label_type) +#define LABEL_IS_DOS (LABEL_DOS == current_label_type) #if ENABLE_FEATURE_SUN_LABEL -#define LABEL_IS_SUN (label_sun == current_label_type) +#define LABEL_IS_SUN (LABEL_SUN == current_label_type) #define STATIC_SUN static #else #define LABEL_IS_SUN 0 @@ -92,7 +92,7 @@ enum label_type { #endif #if ENABLE_FEATURE_SGI_LABEL -#define LABEL_IS_SGI (label_sgi == current_label_type) +#define LABEL_IS_SGI (LABEL_SGI == current_label_type) #define STATIC_SGI static #else #define LABEL_IS_SGI 0 @@ -100,7 +100,7 @@ enum label_type { #endif #if ENABLE_FEATURE_AIX_LABEL -#define LABEL_IS_AIX (label_aix == current_label_type) +#define LABEL_IS_AIX (LABEL_AIX == current_label_type) #define STATIC_AIX static #else #define LABEL_IS_AIX 0 @@ -108,14 +108,14 @@ enum label_type { #endif #if ENABLE_FEATURE_OSF_LABEL -#define LABEL_IS_OSF (label_osf == current_label_type) +#define LABEL_IS_OSF (LABEL_OSF == current_label_type) #define STATIC_OSF static #else #define LABEL_IS_OSF 0 #define STATIC_OSF extern #endif -enum action { fdisk, require, try_only, create_empty_dos, create_empty_sun }; +enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN }; static void update_units(void); #if ENABLE_FEATURE_FDISK_WRITABLE @@ -263,14 +263,15 @@ static const char *const i386_sys_types[] = { NULL }; +enum { + dev_fd = 3 /* the disk */ +}; /* Globals */ - struct globals { char *line_ptr; const char *disk_device; - int fd; /* the disk */ int g_partitions; // = 4; /* maximum partition + 1 */ unsigned units_per_sector; // = 1; unsigned sector_size; // = DEFAULT_SECTOR_SIZE; @@ -295,7 +296,6 @@ struct globals { #define G (*ptr_to_globals) #define line_ptr (G.line_ptr) #define disk_device (G.disk_device ) -#define fd (G.fd ) #define g_partitions (G.g_partitions ) #define units_per_sector (G.units_per_sector ) #define sector_size (G.sector_size ) @@ -323,7 +323,7 @@ struct globals { /* TODO: move to libbb? */ -static ullong bb_BLKGETSIZE_sectors(void) +static ullong bb_BLKGETSIZE_sectors(int fd) { uint64_t v64; unsigned long longsectors; @@ -642,9 +642,6 @@ get_nr_sects(const struct partition *p) return read4_little_endian(p->size4); } -/* normally O_RDWR, -l option gives O_RDONLY */ -static int type_open = O_RDWR; - static int ext_index; /* the prime extended partition */ static smallint listing; /* no aborts for fdisk -l */ static smallint dos_compatible_flag = 1; @@ -663,7 +660,7 @@ static ullong total_number_of_sectors; static void fdisk_fatal(const char *why) { if (listing) { - close(fd); + close(dev_fd); longjmp(listingbuf, 1); } bb_error_msg_and_die(why, disk_device); @@ -674,11 +671,11 @@ seek_sector(ullong secno) { secno *= sector_size; #if ENABLE_FDISK_SUPPORT_LARGE_DISKS - if (lseek64(fd, (off64_t)secno, SEEK_SET) == (off64_t) -1) + if (lseek64(dev_fd, (off64_t)secno, SEEK_SET) == (off64_t) -1) fdisk_fatal(unable_to_seek); #else if (secno > MAXINT(off_t) - || lseek(fd, (off_t)secno, SEEK_SET) == (off_t) -1 + || lseek(dev_fd, (off_t)secno, SEEK_SET) == (off_t) -1 ) { fdisk_fatal(unable_to_seek); } @@ -690,7 +687,7 @@ static void write_sector(ullong secno, char *buf) { seek_sector(secno); - if (write(fd, buf, sector_size) != sector_size) + if (write(dev_fd, buf, sector_size) != sector_size) fdisk_fatal(unable_to_write); } #endif @@ -702,7 +699,7 @@ read_pte(struct pte *pe, ullong offset) pe->offset = offset; pe->sectorbuffer = xmalloc(sector_size); seek_sector(offset); - if (read(fd, pe->sectorbuffer, sector_size) != sector_size) + if (read(dev_fd, pe->sectorbuffer, sector_size) != sector_size) fdisk_fatal(unable_to_read); #if ENABLE_FEATURE_FDISK_WRITABLE pe->changed = 0; @@ -1126,7 +1123,7 @@ create_doslabel(void) printf(msg_building_new_label, "DOS disklabel"); - current_label_type = label_dos; + current_label_type = LABEL_DOS; #if ENABLE_FEATURE_OSF_LABEL possibly_osf_label = 0; @@ -1139,7 +1136,7 @@ create_doslabel(void) extended_offset = 0; set_all_unchanged(); set_changed(0); - get_boot(create_empty_dos); + get_boot(CREATE_EMPTY_DOS); } #endif /* FEATURE_FDISK_WRITABLE */ @@ -1148,7 +1145,7 @@ get_sectorsize(void) { if (!user_set_sector_size) { int arg; - if (ioctl(fd, BLKSSZGET, &arg) == 0) + if (ioctl(dev_fd, BLKSSZGET, &arg) == 0) sector_size = arg; if (sector_size != DEFAULT_SECTOR_SIZE) printf("Note: sector size is %d (not %d)\n", @@ -1161,7 +1158,7 @@ get_kernel_geometry(void) { struct hd_geometry geometry; - if (!ioctl(fd, HDIO_GETGEO, &geometry)) { + if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) { kern_heads = geometry.heads; kern_sectors = geometry.sectors; /* never use geometry.cylinders - it is truncated */ @@ -1224,7 +1221,7 @@ get_geometry(void) g_sectors = user_sectors ? user_sectors : pt_sectors ? pt_sectors : kern_sectors ? kern_sectors : 63; - total_number_of_sectors = bb_BLKGETSIZE_sectors(); + total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd); sector_offset = 1; if (dos_compatible_flag) @@ -1236,7 +1233,9 @@ get_geometry(void) } /* - * Read MBR. Returns: + * Opens disk_device and optionally reads MBR. + * FIXME: document what each 'what' value will do! + * Returns: * -1: no 0xaa55 flag present (possibly entire disk BSD) * 0: found or created label * 1: I/O error @@ -1248,82 +1247,80 @@ static int get_boot(void) #define get_boot(what) get_boot() #endif { - int i; + int i, fd; g_partitions = 4; - for (i = 0; i < 4; i++) { struct pte *pe = &ptes[i]; - pe->part_table = pt_offset(MBRbuffer, i); pe->ext_pointer = NULL; pe->offset = 0; pe->sectorbuffer = MBRbuffer; #if ENABLE_FEATURE_FDISK_WRITABLE - pe->changed = (what == create_empty_dos); + pe->changed = (what == CREATE_EMPTY_DOS); #endif } -#if ENABLE_FEATURE_SUN_LABEL - if (what == create_empty_sun && check_sun_label()) - return 0; -#endif - - memset(MBRbuffer, 0, 512); - #if ENABLE_FEATURE_FDISK_WRITABLE - if (what == create_empty_dos) - goto got_dos_table; /* skip reading disk */ +// ALERT! highly idiotic design! +// We end up here when we call get_boot() recursively +// via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS). +// or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN). +// (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?) +// So skip opening device _again_... + if (what == CREATE_EMPTY_DOS USE_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN)) + goto created_table; + + fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR); - fd = open(disk_device, type_open); if (fd < 0) { fd = open(disk_device, O_RDONLY); if (fd < 0) { - if (what == try_only) + if (what == TRY_ONLY) return 1; fdisk_fatal(unable_to_open); - } else - printf("You will not be able to write " - "the partition table\n"); + } + xmove_fd(fd, dev_fd); + printf("'%s' is opened for read only\n", disk_device); } - - if (512 != read(fd, MBRbuffer, 512)) { - if (what == try_only) + if (512 != read(dev_fd, MBRbuffer, 512)) { + if (what == TRY_ONLY) { + close(dev_fd); return 1; + } fdisk_fatal(unable_to_read); } #else fd = open(disk_device, O_RDONLY); if (fd < 0) return 1; - if (512 != read(fd, MBRbuffer, 512)) + if (512 != read(fd, MBRbuffer, 512)) { + close(fd); return 1; + } + xmove_fd(fd, dev_fd); #endif get_geometry(); - update_units(); #if ENABLE_FEATURE_SUN_LABEL if (check_sun_label()) return 0; #endif - #if ENABLE_FEATURE_SGI_LABEL if (check_sgi_label()) return 0; #endif - #if ENABLE_FEATURE_AIX_LABEL if (check_aix_label()) return 0; #endif - #if ENABLE_FEATURE_OSF_LABEL if (check_osf_label()) { possibly_osf_label = 1; if (!valid_part_table_flag(MBRbuffer)) { - current_label_type = label_osf; + current_label_type = LABEL_OSF; return 0; } printf("This disk has both DOS and BSD magic.\n" @@ -1331,49 +1328,34 @@ static int get_boot(void) } #endif -#if ENABLE_FEATURE_FDISK_WRITABLE - got_dos_table: -#endif - - if (!valid_part_table_flag(MBRbuffer)) { #if !ENABLE_FEATURE_FDISK_WRITABLE + if (!valid_part_table_flag(MBRbuffer)) return -1; #else - switch (what) { - case fdisk: + if (!valid_part_table_flag(MBRbuffer)) { + if (what == OPEN_MAIN) { printf("Device contains neither a valid DOS " "partition table, nor Sun, SGI or OSF " "disklabel\n"); #ifdef __sparc__ -#if ENABLE_FEATURE_SUN_LABEL - create_sunlabel(); -#endif + USE_FEATURE_SUN_LABEL(create_sunlabel();) #else create_doslabel(); #endif return 0; - case try_only: - return -1; - case create_empty_dos: -#if ENABLE_FEATURE_SUN_LABEL - case create_empty_sun: -#endif - break; - default: - bb_error_msg_and_die("internal error"); } -#endif /* FEATURE_FDISK_WRITABLE */ + /* TRY_ONLY: */ + return -1; } + created_table: +#endif /* FEATURE_FDISK_WRITABLE */ -#if ENABLE_FEATURE_FDISK_WRITABLE - warn_cylinders(); -#endif + + USE_FEATURE_FDISK_WRITABLE(warn_cylinders();) warn_geometry(); for (i = 0; i < 4; i++) { - struct pte *pe = &ptes[i]; - - if (IS_EXTENDED(pe->part_table->sys_ind)) { + if (IS_EXTENDED(ptes[i].part_table->sys_ind)) { if (g_partitions != 4) printf("Ignoring extra extended " "partition %d\n", i + 1); @@ -1384,16 +1366,13 @@ static int get_boot(void) for (i = 3; i < g_partitions; i++) { struct pte *pe = &ptes[i]; - if (!valid_part_table_flag(pe->sectorbuffer)) { printf("Warning: invalid flag 0x%02x,0x%02x of partition " "table %d will be corrected by w(rite)\n", pe->sectorbuffer[510], pe->sectorbuffer[511], i + 1); -#if ENABLE_FEATURE_FDISK_WRITABLE - pe->changed = 1; -#endif + USE_FEATURE_FDISK_WRITABLE(pe->changed = 1;) } } @@ -2474,7 +2453,7 @@ reread_partition_table(int leave) printf("Calling ioctl() to re-read partition table\n"); sync(); /* sleep(2); Huh? */ - i = ioctl_or_perror(fd, BLKRRPART, NULL, + i = ioctl_or_perror(dev_fd, BLKRRPART, NULL, "WARNING: rereading partition table " "failed, kernel still uses old table"); #if 0 @@ -2487,7 +2466,7 @@ reread_partition_table(int leave) if (leave) { if (ENABLE_FEATURE_CLEAN_UP) - close(fd); + close(dev_fd); exit(i != 0); } } @@ -2619,7 +2598,8 @@ xselect(void) x_list_table(0); break; case 'q': - close(fd); + if (ENABLE_FEATURE_CLEAN_UP) + close(dev_fd); bb_putchar('\n'); exit(0); case 'r': @@ -2687,7 +2667,7 @@ is_ide_cdrom_or_tape(const char *device) static void -trydev(const char *device, int user_specified) +open_list_and_close(const char *device, int user_specified) { int gb; @@ -2697,46 +2677,44 @@ trydev(const char *device, int user_specified) if (!user_specified) if (is_ide_cdrom_or_tape(device)) return; - fd = open(disk_device, type_open); - if (fd >= 0) { - gb = get_boot(try_only); - if (gb > 0) { /* I/O error */ - close(fd); - } else if (gb < 0) { /* no DOS signature */ - list_disk_geometry(); - if (LABEL_IS_AIX) { - return; - } -#if ENABLE_FEATURE_OSF_LABEL - if (bsd_trydev(device) < 0) -#endif - printf("Disk %s doesn't contain a valid " - "partition table\n", device); - close(fd); - } else { - close(fd); - list_table(0); -#if ENABLE_FEATURE_FDISK_WRITABLE - if (!LABEL_IS_SUN && g_partitions > 4){ - delete_partition(ext_index); - } -#endif - } - } else { + + /* Open disk_device, save file descriptor to dev_fd */ + errno = 0; + gb = get_boot(TRY_ONLY); + if (gb > 0) { /* I/O error */ /* Ignore other errors, since we try IDE and SCSI hard disks which may not be installed on the system. */ - if (errno == EACCES) { - printf("Cannot open %s\n", device); - return; + if (user_specified || errno == EACCES) + bb_perror_msg("can't open '%s'", device); + return; + } + + if (gb < 0) { /* no DOS signature */ + list_disk_geometry(); + if (LABEL_IS_AIX) + goto ret; +#if ENABLE_FEATURE_OSF_LABEL + if (bsd_trydev(device) < 0) +#endif + printf("Disk %s doesn't contain a valid " + "partition table\n", device); + } else { + list_table(0); +#if ENABLE_FEATURE_FDISK_WRITABLE + if (!LABEL_IS_SUN && g_partitions > 4) { + delete_partition(ext_index); } +#endif } + ret: + close(dev_fd); } /* for fdisk -l: try all things in /proc/partitions that look like a partition name (do not end in a digit) */ static void -tryprocpt(void) +list_devs_in_proc_partititons(void) { FILE *procpt; char line[100], ptname[100], devname[120], *s; @@ -2753,7 +2731,7 @@ tryprocpt(void) if (isdigit(s[-1])) continue; sprintf(devname, "/dev/%s", ptname); - trydev(devname, 0); + open_list_and_close(devname, 0); } #if ENABLE_FEATURE_CLEAN_UP fclose(procpt); @@ -2792,6 +2770,8 @@ int fdisk_main(int argc, char **argv) INIT_G(); + close(dev_fd); /* just in case */ + opt_complementary = "b+:C+:H+:S+"; /* numeric params */ opt = getopt32(argv, "b:C:H:lS:u" USE_FEATURE_FDISK_BLKSIZE("s"), §or_size, &user_cylinders, &user_heads, &user_sectors); @@ -2819,16 +2799,15 @@ int fdisk_main(int argc, char **argv) if (opt & OPT_l) { nowarn = 1; #endif - type_open = O_RDONLY; if (*argv) { listing = 1; do { - trydev(*argv, 1); + open_list_and_close(*argv, 1); } while (*++argv); } else { /* we don't have device names, */ /* use /proc/partitions instead */ - tryprocpt(); + list_devs_in_proc_partititons(); } return 0; #if ENABLE_FEATURE_FDISK_WRITABLE @@ -2845,7 +2824,7 @@ int fdisk_main(int argc, char **argv) for (j = 0; j < argc; j++) { unsigned long long size; fd = xopen(argv[j], O_RDONLY); - size = bb_BLKGETSIZE_sectors() / 2; + size = bb_BLKGETSIZE_sectors(fd) / 2; close(fd); if (argc == 1) printf("%lld\n", size); @@ -2861,7 +2840,7 @@ int fdisk_main(int argc, char **argv) bb_show_usage(); disk_device = argv[0]; - get_boot(fdisk); + get_boot(OPEN_MAIN); if (LABEL_IS_OSF) { /* OSF label, and no DOS label */ @@ -2869,7 +2848,7 @@ int fdisk_main(int argc, char **argv) "disklabel mode\n", disk_device); bsd_select(); /*Why do we do this? It seems to be counter-intuitive*/ - current_label_type = label_dos; + current_label_type = LABEL_DOS; /* If we return we may want to make an empty DOS label? */ } @@ -2954,7 +2933,7 @@ int fdisk_main(int argc, char **argv) list_table(0); break; case 'q': - close(fd); + close(dev_fd); bb_putchar('\n'); return 0; case 's': |