From 2b6fc908bc368b540845a313c3b8a867c5ad9a42 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 7 Dec 2006 00:25:35 +0100 Subject: Imported from util-linux-2.8 tarball. --- disk-utils/fdisk.c | 1136 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 798 insertions(+), 338 deletions(-) (limited to 'disk-utils/fdisk.c') diff --git a/disk-utils/fdisk.c b/disk-utils/fdisk.c index 95b958d82..d99a8b452 100644 --- a/disk-utils/fdisk.c +++ b/disk-utils/fdisk.c @@ -49,7 +49,18 @@ * Tue Sep 26 17:07:54 1995: More patches from aeb. Fix segfaults, all >4GB. * Don't destroy random data if extd partition starts past 4GB, aeb, 950818. * Don't segfault on bad partition created by previous fdisk. - * + * Modified, Fri Jul 14 11:13:35 MET DST 1996, jj@sunsite.mff.cuni.cz: + * editor for Sun disklabels. + * Modified, Wed Jul 3 10:14:17 MET DST 1996, jj@sunsite.mff.cuni.cz: + * support for Sun floppies + * Modified, Thu Jul 24 16:42:33 MET DST 1997, fasten@shw.com: + * LINUX_EXTENDED support + * Added Windows 95 partition types, aeb. + * Fixed a bug described by johnf@whitsunday.net.au, aeb, 980408. + * [There are lots of other bugs - nobody should use this program] + * [cfdisk on the other hand is nice and correct] + * Try to avoid reading a CD-ROM. + * Do not print Begin column -- it confuses too many people -- aeb, 980610. */ @@ -61,14 +72,18 @@ #include #include #include +#include +#include #include -#include -#include -#include +#include /* for HDIO_GETGEO */ +#include /* for BLKRRPART, BLKGETSIZE */ #include "fdisk.h" +#if defined(sparc) +#include "fdisksunlabel.h" +#endif #define hex_val(c) ({ \ char _c = (c); \ @@ -77,14 +92,11 @@ }) -#define VERSION "2.1 (>4GB)" +#define VERSION "2.8" /* util-linux version */ #define DEFAULT_DEVICE "/dev/hda" #define ALTERNATE_DEVICE "/dev/sda" #define LINE_LENGTH 80 -#define MAXIMUM_PARTS 60 -#define PART_TABLE_FLAG 0xaa55 -#define table_check(b) ((unsigned short *)((b) + 0x1fe)) #define offset(b, n) ((struct partition *)((b) + 0x1be + \ (n) * sizeof(struct partition))) #define sector(s) ((s) & 0x3f) @@ -101,12 +113,70 @@ s |= (sector >> 2) & 0xc0; \ } +/* A valid partition table sector ends in 0x55 0xaa */ +unsigned int +part_table_flag(char *b) { + return ((uint) b[510]) + (((uint) b[511]) << 8); +} + +int +valid_part_table_flag(unsigned char *b) { + return (b[510] == 0x55 && b[511] == 0xaa); +} + +void +write_part_table_flag(char *b) { + b[510] = 0x55; + b[511] = 0xaa; +} + +/* start_sect and nr_sects are stored little endian on all machines */ +/* moreover, they are not aligned correctly */ +void +store4_little_endian(unsigned char *cp, unsigned int val) { + cp[0] = (val & 0xff); + cp[1] = ((val >> 8) & 0xff); + cp[2] = ((val >> 16) & 0xff); + cp[3] = ((val >> 24) & 0xff); +} + +unsigned int +read4_little_endian(unsigned char *cp) { + return (uint)(cp[0]) + ((uint)(cp[1]) << 8) + + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24); +} + +void +set_start_sect(struct partition *p, unsigned int start_sect) { + store4_little_endian(p->start4, start_sect); +} + +unsigned int +get_start_sect(struct partition *p) { + return read4_little_endian(p->start4); +} + +void +set_nr_sects(struct partition *p, unsigned int nr_sects) { + store4_little_endian(p->size4, nr_sects); +} + +unsigned int +get_nr_sects(struct partition *p) { + return read4_little_endian(p->size4); +} + #define ACTIVE_FLAG 0x80 -#define EXTENDED 5 +#define EXTENDED 0x05 +#define WIN98_EXTENDED 0x0f #define LINUX_PARTITION 0x81 #define LINUX_SWAP 0x82 #define LINUX_NATIVE 0x83 +#define LINUX_EXTENDED 0x85 + +#define IS_EXTENDED(i) \ + ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED) /* normally O_RDWR, -l option gives O_RDONLY */ static int type_open = O_RDWR; @@ -122,6 +192,8 @@ char *disk_device = DEFAULT_DEVICE, /* hda, unless specified */ int fd, /* the disk */ ext_index, /* the prime extended partition */ listing = 0, /* no aborts for fdisk -l */ + nowarn = 0, /* no warnings for fdisk -l/-s */ + show_begin = 0, dos_compatible_flag = ~0, partitions = 4; /* maximum partition + 1 */ @@ -135,51 +207,59 @@ uint heads, extended_offset = 0, /* offset of link pointers */ offsets[MAXIMUM_PARTS] = {0, 0, 0, 0}; +int sun_label = 0; /* looking at sun disklabel */ + struct partition *part_table[MAXIMUM_PARTS] /* partitions */ = {offset(buffer, 0), offset(buffer, 1), offset(buffer, 2), offset(buffer, 3)}, *ext_pointers[MAXIMUM_PARTS] /* link pointers */ = {NULL, NULL, NULL, NULL}; -struct systypes sys_types[] = { /* struct systypes in fdisk.h *//* bf */ - {0, "Empty"}, - {1, "DOS 12-bit FAT"}, - {2, "XENIX root"}, - {3, "XENIX usr"}, - {4, "DOS 16-bit <32M"}, - {EXTENDED, "Extended"}, - {6, "DOS 16-bit >=32M"}, - {7, "OS/2 HPFS"}, /* or QNX? */ - {8, "AIX"}, - {9, "AIX bootable"}, - {10, "OS/2 Boot Manager"}, - {0x40, "Venix 80286"}, - {0x51, "Novell?"}, - {0x52, "Microport"}, /* or CPM? */ - {0x63, "GNU HURD"}, /* or System V/386? */ - {0x64, "Novell Netware 286"}, - {0x65, "Novell Netware 386"}, - {0x75, "PC/IX"}, - {0x80, "Old MINIX"}, /* Minix 1.4a and earlier */ - - {LINUX_PARTITION, "Linux/MINIX"}, /* Minix 1.4b and later */ - {LINUX_SWAP, "Linux swap"}, - {LINUX_NATIVE, "Linux native"}, - - {0x93, "Amoeba"}, - {0x94, "Amoeba BBT"}, /* (bad block table) */ - {0xa5, "BSD/386"}, - {0xb7, "BSDI fs"}, - {0xb8, "BSDI swap"}, - {0xc7, "Syrinx"}, - {0xdb, "CP/M"}, /* or Concurrent DOS? */ - {0xe1, "DOS access"}, - {0xe3, "DOS R/O"}, - {0xf2, "DOS secondary"}, - {0xff, "BBT"} /* (bad track table) */ - }; - -int nsys_types = sizeof (sys_types) / sizeof (struct systypes); /* bf */ +struct systypes sys_types[] = { + {0x00, "Empty"}, + {0x01, "DOS 12-bit FAT"}, + {0x02, "XENIX root"}, + {0x03, "XENIX usr"}, + {0x04, "DOS 16-bit <32M"}, + {0x05, "Extended"}, + {0x06, "DOS 16-bit >=32M"}, + {0x07, "OS/2 HPFS"}, /* or QNX? */ + {0x08, "AIX"}, + {0x09, "AIX bootable"}, + {0x0a, "OS/2 Boot Manager"}, + {0x0b, "Win95 FAT32"}, + {0x0c, "Win95 FAT32 (LBA)"}, + {0x0e, "Win95 FAT16 (LBA)"}, + {0x0f, "Win95 Extended (LBA)"}, + {0x40, "Venix 80286"}, + {0x51, "Novell?"}, + {0x52, "Microport"}, /* or CPM? */ + {0x63, "GNU HURD"}, /* or System V/386? */ + {0x64, "Novell Netware 286"}, + {0x65, "Novell Netware 386"}, + {0x75, "PC/IX"}, + {0x80, "Old MINIX"}, /* Minix 1.4a and earlier */ + + {LINUX_PARTITION, "Linux/MINIX"}, /* Minix 1.4b and later */ + {LINUX_SWAP, "Linux swap"}, + {LINUX_NATIVE, "Linux native"}, + {LINUX_EXTENDED, "Linux extended"}, + + {0x93, "Amoeba"}, + {0x94, "Amoeba BBT"}, /* (bad block table) */ + {0xa5, "BSD/386"}, + {0xa6, "OpenBSD"}, + {0xa7, "NEXTSTEP"}, + {0xb7, "BSDI fs"}, + {0xb8, "BSDI swap"}, + {0xc7, "Syrinx"}, + {0xdb, "CP/M"}, /* or Concurrent DOS? */ + {0xe1, "DOS access"}, + {0xe3, "DOS R/O"}, + {0xf2, "DOS secondary"}, + {0xff, "BBT"}, /* (bad track table) */ + { 0, NULL } +}; jmp_buf listingbuf; @@ -195,7 +275,10 @@ void fatal(enum failure why) switch (why) { case usage: message = - "Usage: fdisk [-l] [-v] [-s /dev/hdxn] [/dev/hdx]\n"; +"Usage: fdisk [-b] [-u] [/dev/hdx] Change partition table\n" +" fdisk -l [-b] [-u] [/dev/hdx] List partition table(s)\n" +" fdisk -s /dev/hdxn Give partition size(s)\n" +" fdisk -v Give fdisk version\n"; break; case unable_to_open: sprintf(error, "Unable to open %s\n", disk_device); @@ -222,14 +305,35 @@ void fatal(enum failure why) void menu(void) { - puts("Command action\n" + if (sun_label) + puts("Command action\n" + " a toggle a read only flag\n" /* sun */ + " b edit bsd disklabel\n" + " c toggle the mountable flag\n" /* sun */ + " d delete a partition\n" + " l list known partition types\n" + " m print this menu\n" + " n add a new partition\n" + " o create a new empty DOS partition table\n" + " p print the partition table\n" + " q quit without saving changes\n" + " s create a new empty Sun disklabel\n" /* sun */ + " t change a partition's system id\n" + " u change display/entry units\n" + " v verify the partition table\n" + " w write table to disk and exit\n" + " x extra functionality (experts only)" + ); + else + puts("Command action\n" " a toggle a bootable flag\n" - " b edit bsd disklabel\n" /* bf */ + " b edit bsd disklabel\n" " c toggle the dos compatibility flag\n" " d delete a partition\n" " l list known partition types\n" " m print this menu\n" " n add a new partition\n" + " o create a new empty DOS partition table\n" " p print the partition table\n" " q quit without saving changes\n" " t change a partition's system id\n" @@ -237,16 +341,35 @@ void menu(void) " v verify the partition table\n" " w write table to disk and exit\n" " x extra functionality (experts only)" - ); + ); } void xmenu(void) { - puts("Command action\n" - " b move beginning of data in a partition\n" + if (sun_label) + puts("Command action\n" + " a change number of alternate cylinders\n" /* sun */ + " c change number of cylinders\n" + " d print the raw data in the partition table\n" + " e change number of extra sectors per cylinder\n" /*sun*/ + " h change number of heads\n" + " i change interleave factor\n" /* sun */ + " o change rotation speed (rpm)\n" /* sun */ + " m print this menu\n" + " p print the partition table\n" + " q quit without saving changes\n" + " r return to main menu\n" + " s change number of sectors\n" + " v verify the partition table\n" + " w write table to disk and exit\n" + " y change number of physical cylinders" /* sun */ + ); + else + puts("Command action\n" + " b move beginning of data in a partition\n" /* !sun */ " c change number of cylinders\n" " d print the raw data in the partition table\n" - " e list extended partitions\n" + " e list extended partitions\n" /* sun */ " h change number of heads\n" " m print this menu\n" " p print the partition table\n" @@ -255,34 +378,36 @@ void xmenu(void) " s change number of sectors\n" " v verify the partition table\n" " w write table to disk and exit" - ); + ); } char *partition_type(unsigned char type) { - int high = sizeof(sys_types) / sizeof(struct systypes), - low = 0, mid; - uint tmp; - - while (high >= low) { - mid = (high + low) >> 1; - if ((tmp = sys_types[mid].index) == type) - return sys_types[mid].name; - else if (tmp < type) - low = mid + 1; - else high = mid - 1; - } + int i; + struct systypes *types; + +#if defined(sparc) + if (sun_label) + types = sun_sys_types; + else +#endif + types = sys_types; + + for (i=0; types[i].name; i++) + if (types[i].index == type) + return types[i].name; + return NULL; } -/* added parameters to list_types() so fdisklabel - can pass another list of types. -*//* bf */ -void list_types(struct systypes *sys, int size) +void list_types(struct systypes *sys) { - uint last[4], done = 0, next = 0; + uint last[4], done = 0, next = 0, size; int i; + for (i = 0; sys[i].name; i++); + size = i; + for (i = 3; i >= 0; i--) last[3 - i] = done += (size + i - done) / (i + 1); i = done = 0; @@ -309,17 +434,17 @@ void clear_partition(struct partition *p) p->end_head = 0; p->end_sector = 0; p->end_cyl = 0; - p->start_sect = 0; - p->nr_sects = 0; + set_start_sect(p,0); + set_nr_sects(p,0); } void set_partition(int i, struct partition *p, uint start, uint stop, - int sys, uint offset) + int sysid, uint offset) { p->boot_ind = 0; - p->sys_ind = sys; - p->start_sect = start - offset; - p->nr_sects = stop - start + 1; + p->sys_ind = sysid; + set_start_sect(p, start - offset); + set_nr_sects(p, stop - start + 1); if (dos_compatible_flag && (start/(sectors*heads) > 1023)) start = heads*sectors*1024 - 1; set_hsc(p->head, p->sector, p->cyl, start); @@ -380,13 +505,13 @@ void update_units(void) void warn_cylinders(void) { - update_units(); - if (cylinders > 1024) - fprintf(stderr, "The number of cylinders for this disk is " - "set to %d.\nThis is larger than 1024, and may cause " + if (!sun_label && cylinders > 1024 && !nowarn) + fprintf(stderr, + "The number of cylinders for this disk is set to %d.\n" + "This is larger than 1024, and may cause " "problems with:\n" "1) software that runs at boot time (e.g., LILO)\n" - "2) booting and partitioning software form other OSs\n" + "2) booting and partitioning software from other OSs\n" " (e.g., DOS FDISK, OS/2 FDISK)\n", cylinders); } @@ -397,9 +522,9 @@ void read_extended(struct partition *p) struct partition *q; ext_pointers[ext_index] = part_table[ext_index]; - if (!p->start_sect) + if (!get_start_sect(p)) fprintf(stderr, "Bad offset in primary extended partition\n"); - else while (p->sys_ind == EXTENDED) { + else while (IS_EXTENDED (p->sys_ind)) { if (partitions >= MAXIMUM_PARTS) { fprintf(stderr, "Warning: deleting partitions after %d\n", @@ -408,9 +533,9 @@ void read_extended(struct partition *p) changed[partitions - 1] = 1; return; } - offsets[partitions] = extended_offset + p->start_sect; + offsets[partitions] = extended_offset + get_start_sect(p); if (!extended_offset) - extended_offset = p->start_sect; + extended_offset = get_start_sect(p); if (ext2_llseek(fd, (ext2_loff_t)offsets[partitions] * SECTOR_SIZE, SEEK_SET) < 0) fatal(unable_to_seek); @@ -421,7 +546,7 @@ void read_extended(struct partition *p) part_table[partitions] = ext_pointers[partitions] = NULL; q = p = offset(buffers[partitions], 0); for (i = 0; i < 4; i++, p++) { - if (p->sys_ind == EXTENDED) + if (IS_EXTENDED (p->sys_ind)) if (ext_pointers[partitions]) fprintf(stderr, "Warning: extra link " "pointer in partition table " @@ -449,19 +574,50 @@ void read_extended(struct partition *p) } } -int get_boot(void) +void create_doslabel(void) +{ + int i; + + fprintf(stderr, + "Building a new DOS disklabel. Changes will remain in memory only,\n" + "until you decide to write them. After that, of course, the previous\n" + "content won't be recoverable.\n\n"); + + write_part_table_flag(buffer); + for (i = 0; i < 4; i++) + clear_partition(part_table[i]); + for (i = 1; i < MAXIMUM_PARTS; i++) + changed[i] = 0; + changed[0] = 1; + get_boot(create_empty); +} + +/* + * Read MBR. Returns: + * -1: no 0xaa55 flag present (possibly entire disk BSD) + * 0: found or created label + */ +int get_boot(enum action what) { int i; struct hd_geometry geometry; partitions = 4; - if ((fd = open(disk_device, type_open)) < 0) - { + + if (what == create_empty) + goto got_table; /* skip reading disk */ + + if ((fd = open(disk_device, type_open)) < 0) { if ((fd = open(disk_device, O_RDONLY)) < 0) fatal(unable_to_open); else printf("You will not be able to write the partition table.\n"); } + +#if defined(sparc) + guess_device_type(fd); +#endif + if (SECTOR_SIZE != read(fd, buffer, SECTOR_SIZE)) fatal(unable_to_read); @@ -475,31 +631,67 @@ int get_boot(void) cylinders = geometry.cylinders; if (dos_compatible_flag) sector_offset = sectors; - warn_cylinders(); + } else { + if (!ioctl(fd, BLKGETSIZE, §ors)) { + heads = 1; + cylinders = 1; + } else { + heads = cylinders = sectors = 0; + } } - else update_units(); - warn_geometry(); + update_units(); + +got_table: - if (*(unsigned short *) (0x1fe + buffer) != 0xAA55) { - return 0; /* not a valid partition table */ +#if defined(sparc) + if (check_sun_label()) + return 0; +#endif + + if (!valid_part_table_flag(buffer)) { + switch(what) { + case fdisk: + fprintf(stderr, + "Device contains neither a valid DOS partition" + " table, nor Sun disklabel\n"); +#ifdef __sparc__ + create_sunlabel(); +#else + create_doslabel(); +#endif + return 0; + case require: + return -1; + case try_only: + return -1; + case create_empty: + break; + } + + fprintf(stderr, "Internal error\n"); + exit(1); } + warn_cylinders(); + warn_geometry(); + for (i = 0; i < 4; i++) - if(part_table[i]->sys_ind == EXTENDED) + if(IS_EXTENDED (part_table[i]->sys_ind)) if (partitions != 4) fprintf(stderr, "Ignoring extra extended " "partition %d\n", i + 1); else read_extended(part_table[ext_index = i]); for (i = 3; i < partitions; i++) - if (*table_check(buffers[i]) != PART_TABLE_FLAG) { - fprintf(stderr, "Warning: invalid flag %04x of parti" - "tion table %d will be corrected by w(rite)\n", - *table_check(buffers[i]), i + 1); + if (!valid_part_table_flag(buffers[i])) { + fprintf(stderr, + "Warning: invalid flag 0x%04x of partition " + "table %d will be corrected by w(rite)\n", + part_table_flag(buffers[i]), i + 1); changed[i] = 1; } - return 1; + return 0; } int read_line(void) @@ -514,14 +706,23 @@ int read_line(void) char read_char(char *mesg) { - do + do { fputs(mesg, stdout); - while (!read_line()); + } while (!read_line()); return *line_ptr; } -/* new function *//* bf */ -int read_hex(struct systypes *sys, int size) +char read_chars(char *mesg) +{ + fputs(mesg, stdout); + if (!read_line()) { + *line_ptr = '\n'; + return '\n'; + } else + return *line_ptr; +} + +int read_hex(struct systypes *sys) { int hex; @@ -529,7 +730,7 @@ int read_hex(struct systypes *sys, int size) { read_char("Hex code (type L to list codes): "); if (tolower(*line_ptr) == 'l') - list_types(sys, size); + list_types(sys); else if (isxdigit (*line_ptr)) { hex = 0; @@ -563,9 +764,17 @@ uint read_int(uint low, uint dflt, uint high, enum offset base, char *mesg) } while (1) { - while (!isdigit(read_char(ms)) - && (*line_ptr != '-' && *line_ptr != '+')) - continue; + if (base == deflt) { + while (read_chars(ms) != '\n' && !isdigit(*line_ptr) + && *line_ptr != '-' && *line_ptr != '+') + continue; + if (*line_ptr == '\n') + return dflt; + } else { + while (!isdigit(read_char(ms)) + && *line_ptr != '-' && *line_ptr != '+') + continue; + } if (*line_ptr == '+' || *line_ptr == '-') { if (*line_ptr == '+') ++line_ptr; @@ -624,9 +833,14 @@ int get_partition(int warn, int max) */ int i = read_int(1, max, max, ignore, "Partition number") - 1; - if (warn && !part_table[i]->sys_ind) - fprintf(stderr, "Warning: partition %d has empty type\n", - i + 1); + if (warn && ( + (!sun_label && !part_table[i]->sys_ind) +#if defined(sparc) + || (sun_label && + (!sunlabel->partitions[i].num_sectors || + !sunlabel->infos[i].id)) +#endif + )) fprintf(stderr, "Warning: partition %d has empty type\n", i+1); return i; } @@ -649,7 +863,7 @@ void toggle_active(int i) { struct partition *p = part_table[i]; - if (p->sys_ind == EXTENDED && !p->boot_ind) + if (IS_EXTENDED (p->sys_ind) && !p->boot_ind) fprintf(stderr, "WARNING: Partition %d is an extended partition\n", i + 1); @@ -683,8 +897,14 @@ void delete_partition(int i) if (warn_geometry()) return; changed[i] = 1; +#if defined(sparc) + if (sun_label) { + sun_delete_partition(i); + return; + } +#endif if (i < 4) { - if (p->sys_ind == EXTENDED && i == ext_index) { + if (IS_EXTENDED (p->sys_ind) && i == ext_index) { while (partitions > 4) free(buffers[--partitions]); ext_pointers[ext_index] = NULL; @@ -707,14 +927,14 @@ void delete_partition(int i) p->end_head = q->end_head; p->end_sector = q->end_sector; p->end_cyl = q->end_cyl; - p->start_sect = q->start_sect; - p->nr_sects = q->nr_sects; + set_start_sect(p, get_start_sect(q)); + set_nr_sects(p, get_nr_sects(q)); changed[i - 1] = 1; - } - else { - if(part_table[5]) /* prevent SEGFAULT */ - part_table[5]->start_sect += - offsets[5] - extended_offset; + } else { + if(part_table[5]) /* prevent SEGFAULT */ + set_start_sect(part_table[5], + get_start_sect(part_table[5]) + + offsets[5] - extended_offset); offsets[5] = extended_offset; changed[5] = 1; } @@ -738,53 +958,65 @@ void delete_partition(int i) void change_sysid(void) { char *temp; - int i = get_partition(0, partitions), sys; + int i = get_partition(0, partitions), sys, origsys; struct partition *p = part_table[i]; - if ((sys = p->sys_ind) == EXTENDED) - printf("Partition %d is extended. Delete it\n", i + 1); - else if (!sys) - printf("Partition %d does not exist yet!\n", i + 1); - else while (1) { -#if 0 - read_char("Hex code (type L to list codes): "); - if (tolower(*line_ptr) == 'l') - list_types(); - else if (isxdigit(*line_ptr)) { - sys = 0; - do - sys = sys << 4 | hex_val(*line_ptr++); - while (isxdigit(*line_ptr)); +#if defined(sparc) + if (sun_label) + sys = sunlabel->infos[i].id; + else +#endif + sys = p->sys_ind; + origsys = sys; + + if (!sys) + printf("Partition %d does not exist yet!\n", i + 1); + else while (1) { + if (!sun_label) + sys = read_hex (sys_types); +#if defined(sparc) + else + sys = read_hex (sun_sys_types); #endif - /* The above code has been moved to read_hex () - to avoid having the same code in fdisklabel. - *//* bf */ - sys = read_hex (sys_types, nsys_types); /* bf */ - if (!sys) { - delete_partition(i); - break; - } - else if (sys == EXTENDED) { - printf("You may not change a partition " - "to be an extended partition\n"); - break; - } - else if (sys < 256) { - if (sys == p->sys_ind) - break; - part_table[i]->sys_ind = sys; - printf ("Changed system type of partition %d " - "to %x (%s)\n", i + 1, sys, - (temp = partition_type(sys)) ? temp : - "Unknown"); - changed[i] = 1; + if (!sys) { + delete_partition(i); + break; + } + + if (!sun_label) { + if (IS_EXTENDED (sys) != IS_EXTENDED (p->sys_ind)) { + printf("You cannot change a partition into" + " an extended one or vice versa\n" + "Delete it first.\n"); break; } -#if 0 /* see above *//* bf */ } + + if (sys < 256) { +#if defined(sparc) + if (sun_label && i == 2 && sys != WHOLE_DISK) + printf("Consider leaving partition 3 " + "as Whole disk (5),\n" + "as SunOS/Solaris expects it and " + "even Linux likes it.\n"); #endif - } + if (sys == origsys) + break; +#if defined(sparc) + if (sunlabel) { + sun_change_sysid(i, sys); + } else +#endif + part_table[i]->sys_ind = sys; + printf ("Changed system type of partition %d " + "to %x (%s)\n", i + 1, sys, + (temp = partition_type(sys)) ? temp : + "Unknown"); + changed[i] = 1; + break; + } + } } /* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993, @@ -823,10 +1055,10 @@ static void check_consistency(struct partition *p, int partition) pes = p->end_sector & 0x3f; /* compute logical beginning (c, h, s) */ - long2chs(p->start_sect, &lbc, &lbh, &lbs); + long2chs(get_start_sect(p), &lbc, &lbh, &lbs); /* compute logical ending (c, h, s) */ - long2chs(p->start_sect + p->nr_sects - 1, &lec, &leh, &les); + long2chs(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)) { @@ -864,37 +1096,52 @@ static void check_consistency(struct partition *p, int partition) } } -void list_table(void) +void list_table(int xtra) { struct partition *p; char *type; - int i, w = strlen(disk_device); + int i, w; + +#if defined(sparc) + if (sun_label) + sun_list_table(xtra); + return; +#endif + + w = strlen(disk_device); printf("\nDisk %s: %d heads, %d sectors, %d cylinders\nUnits = " "%ss of %d * 512 bytes\n\n", disk_device, heads, sectors, cylinders, str_units(), display_factor); if (w < 5) w = 5; - printf("%*s Boot Begin Start End Blocks Id System\n", - w + 1, "Device"); - for (i = 0 ; i < partitions; i++) + printf("%*s Boot %s Start End Blocks Id System\n", + w + 1, "Device", show_begin ? " Begin " : " "); + + for (i = 0 ; i < partitions; i++) { if ((p = part_table[i])->sys_ind) { - printf("%*s%-2d %c%9d%9d%9d%9d%c %2x %s\n", w, -/* device */ disk_device, i + 1, + unsigned int psects = get_nr_sects(p); + printf( + show_begin + ? "%*s%-2d %c%9d%9d%9d%9d%c %2x %s\n" + : "%*s%-2d %c%c%9d%9d%9d%c %2x %s\n", +/* device */ w, disk_device, i+1, /* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG ? '*' : '?', + show_begin ? /* begin */ cround(rounded( calculate(p->head, p->sector, p->cyl), - p->start_sect + offsets[i])), -/* start */ cround(p->start_sect + offsets[i]), -/* end */ cround(p->start_sect + offsets[i] + p->nr_sects - - (p->nr_sects ? 1: 0)), -/* odd flag on end */ p->nr_sects / 2, p->nr_sects & 1 ? '+' : ' ', + get_start_sect(p) + offsets[i])) + : ' ', +/* start */ cround(get_start_sect(p) + offsets[i]), +/* end */ cround(get_start_sect(p) + offsets[i] + psects + - (psects ? 1 : 0)), +/* odd flag on end */ psects / 2, (psects & 1) ? '+' : ' ', /* type id */ p->sys_ind, /* type name */ (type = partition_type(p->sys_ind)) ? type : "Unknown"); check_consistency(p, i); } - + } } void x_list_table(int extend) @@ -917,7 +1164,7 @@ void x_list_table(int extend) cylinder(p->sector, p->cyl), p->end_head, sector(p->end_sector), cylinder(p->end_sector, p->end_cyl), - p->start_sect, p->nr_sects, p->sys_ind); + get_start_sect(p), get_nr_sects(p), p->sys_ind); if (p->sys_ind) check_consistency(p, i); } @@ -931,16 +1178,17 @@ void check_bounds(uint *first, uint *last) partition crossing cylinder 8064 */ struct partition *p = part_table[0]; - for (i = 0; i < partitions; p = part_table[++i]) - if (!p->sys_ind || p->sys_ind == EXTENDED) { + for (i = 0; i < partitions; p = part_table[++i]) { + if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) { first[i] = max; last[i] = 0; - } - else { + } else { first[i] = rounded(calculate(p->head, p->sector, - p->cyl), p->start_sect + offsets[i]); - last[i] = p->start_sect + offsets[i] + p->nr_sects - 1; + p->cyl), get_start_sect(p) + offsets[i]); + last[i] = get_start_sect(p) + offsets[i] + + get_nr_sects(p) - 1; } + } } void check(int n, uint h, uint s, uint c, uint start) @@ -984,11 +1232,17 @@ void verify(void) if (warn_geometry()) return; +#if defined(sparc) + if (sun_label) + verify_sun(); + return; +#endif + check_bounds(first, last); for (i = 0; i < partitions; p = part_table[++i]) - if (p->sys_ind && (p->sys_ind != EXTENDED)) { + if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) { check_consistency(p, i); - if (p->start_sect + offsets[i] < first[i]) + if (get_start_sect(p) + offsets[i] < 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, @@ -1007,8 +1261,8 @@ void verify(void) } if (extended_offset) { - uint e_last = part_table[ext_index]->start_sect + - part_table[ext_index]->nr_sects - 1; + uint e_last = get_start_sect(part_table[ext_index]) + + get_nr_sects(part_table[ext_index]) - 1; for (p = part_table[i = 4]; i < partitions; p = part_table[++i]) { @@ -1051,12 +1305,12 @@ void add_partition(int n, int sys) limit = heads * sectors * cylinders - 1; if (extended_offset) { first[ext_index] = extended_offset; - last[ext_index] = q->start_sect + q->nr_sects - 1; + last[ext_index] = get_start_sect(q) + + get_nr_sects(q) - 1; } - } - else { + } else { start = extended_offset + sector_offset; - limit = q->start_sect + q->nr_sects - 1; + limit = get_start_sect(q) + get_nr_sects(q) - 1; } if (unit_flag) for (i = 0; i < partitions; i++) @@ -1066,30 +1320,30 @@ void add_partition(int n, int sys) do { temp = start; for (i = 0; i < partitions; i++) { + int lastplusoff; + if (start == offsets[i]) start += sector_offset; - if (start >= first[i] && start <= last[i]) - if (n < 4) - start = last[i] + 1; - else - start = last[i] + sector_offset; + lastplusoff = last[i] + ((n<4) ? 0 : sector_offset); + if (start >= first[i] && start <= lastplusoff) + start = lastplusoff + 1; } if (start > limit) break; - if (start != temp && read) { + if (start >= temp+display_factor && read) { printf("Sector %d is already allocated\n", temp); - temp = start = stop; + temp = start; read = 0; } if (!read && start == temp) { uint i; - i = (stop = start) + (n > 4); + i = start; start = read_int(cround(i), cround(i), cround(limit), ignore, mesg); if (unit_flag) { start = (start - 1) * display_factor; if (start < i) start = i; - } + } read = 1; } } while (start != temp || !read); @@ -1126,7 +1380,7 @@ void add_partition(int n, int sys) set_partition(n, p, start, stop, sys, offsets[n]); - if (sys == EXTENDED) { + if (IS_EXTENDED (sys)) { ext_index = n; offsets[4] = extended_offset = start; ext_pointers[n] = p; @@ -1143,7 +1397,7 @@ void add_partition(int n, int sys) start - sector_offset, stop, EXTENDED, extended_offset); #if 0 - if ((limit = p->nr_sects) & 1) + if ((limit = get_nr_sects(p)) & 1) printf("Warning: partition %d has an odd " "number of sectors.\n", n + 1); #endif @@ -1169,6 +1423,13 @@ void new_partition(void) if (warn_geometry()) return; + +#if defined(sparc) + if (sun_label) + add_sun_partition(get_partition(0, partitions), LINUX_NATIVE); + return; +#endif + if (partitions >= MAXIMUM_PARTS) { printf("The maximum number of partitions has been created\n"); return; @@ -1214,14 +1475,24 @@ void write_table(void) int i, error = 0; changed[3] = changed[0] || changed[1] || changed[2] || changed[3]; - for (i = 3; i < partitions; i++) + if (!sun_label) { + for (i = 3; i < partitions; i++) { if (changed[i]) { - *table_check(buffers[i]) = PART_TABLE_FLAG; + write_part_table_flag(buffers[i]); if (ext2_llseek(fd, (ext2_loff_t)offsets[i] * SECTOR_SIZE, SEEK_SET) < 0) fatal(unable_to_seek); if (write(fd, buffers[i], SECTOR_SIZE) != SECTOR_SIZE) fatal(unable_to_write); + } + } + } else { +#if defined(sparc) + if (changed[3] || changed[4] || changed[5] || + changed[6] || changed[7]) { + sun_write_table(); + } +#endif } printf("The partition table has been altered!\n\n"); @@ -1252,9 +1523,11 @@ void write_table(void) "system to ensure the partition table is updated.\n", error, strerror(error)); - printf( "\nWARNING: If you have created or modified any DOS 6.x\n" + if (!sun_label) + printf( + "\nWARNING: If you have created or modified any DOS 6.x\n" "partitions, please see the fdisk manual page for additional\n" - "information.\n" ); + "information.\n"); exit(0); } @@ -1284,7 +1557,9 @@ void print_raw(void) int i; printf("Device: %s\n", disk_device); - for (i = 3; i < partitions; i++) + if (sun_label) + print_buffer(buffer); + else for (i = 3; i < partitions; i++) print_buffer(buffers[i]); } @@ -1295,20 +1570,20 @@ void move_begin(int i) if (warn_geometry()) return; - if (!p->sys_ind || !p->nr_sects || p->sys_ind == EXTENDED) { + if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED (p->sys_ind)) { printf("Partition %d has no data area\n", i + 1); return; } - first = rounded(calculate(p->head, p->sector, p->cyl), p->start_sect + - offsets[i]); + first = rounded(calculate(p->head, p->sector, p->cyl), + get_start_sect(p) + offsets[i]); new = read_int(first, first, - p->start_sect + p->nr_sects + offsets[i] - 1, + get_start_sect(p) + get_nr_sects(p) + offsets[i] - 1, lower, "New beginning of data") - offsets[i]; - if (new != p->nr_sects) { - first = p->nr_sects + p->start_sect - new; - p->nr_sects = first; - p->start_sect = new; + if (new != get_nr_sects(p)) { + first = get_nr_sects(p) + get_start_sect(p) - new; + set_nr_sects(p, first); + set_start_sect(p, new); changed[i] = 1; } } @@ -1318,56 +1593,138 @@ void xselect(void) while(1) { putchar('\n'); switch (tolower(read_char("Expert command (m for help): "))) { - case 'b': move_begin(get_partition(0, partitions)); - break; - case 'c': cylinders = read_int(1, cylinders, 65535, - deflt, "Number of cylinders"); - warn_cylinders(); - break; - case 'd': print_raw(); - break; - case 'e': x_list_table(1); - break; - case 'h': heads = read_int(1, heads, 256, deflt, - "Number of heads"); - update_units(); - break; - case 'p': x_list_table(0); - break; - case 'q': close(fd); - exit(0); - case 'r': return; - case 's': sectors = read_int(1, sectors, 63, deflt, - "Number of sectors"); - if (dos_compatible_flag) { - sector_offset = sectors; - fprintf(stderr, "Warning: setting " - "sector offset for DOS " - "compatiblity\n"); - } - update_units(); - break; - case 'v': verify(); - break; - case 'w': write_table(); - default: xmenu(); +#if defined(sparc) + case 'a': + if (sun_label) + sun_set_alt_cyl(); + break; +#endif + case 'b': + if (!sun_label) + move_begin(get_partition(0, partitions)); + break; + case 'c': + cylinders = read_int(1, cylinders, 65535, + deflt, "Number of cylinders"); +#if defined(sparc) + if (sun_label) + sun_set_ncyl(cylinders); +#endif + warn_cylinders(); + break; + case 'd': + print_raw(); + break; + case 'e': + if (!sun_label) + x_list_table(1); +#if defined(sparc) + else + sun_set_xcyl(); +#endif + break; + case 'h': + heads = read_int(1, heads, 256, deflt, + "Number of heads"); + update_units(); + break; +#if defined(sparc) + case 'i': + if (sun_label) + sun_set_ilfact(); + break; + case 'o': + if (sun_label) + sun_set_rspeed(); + break; +#endif + case 'p': +#if defined(sparc) + if (sun_label) + list_table(1); + else +#endif + x_list_table(0); + break; + case 'q': + close(fd); + exit(0); + case 'r': + return; + case 's': + sectors = read_int(1, sectors, 63, deflt, + "Number of sectors"); + if (dos_compatible_flag) { + sector_offset = sectors; + fprintf(stderr, "Warning: setting " + "sector offset for DOS " + "compatiblity\n"); + } + update_units(); + break; + case 'v': + verify(); + break; + case 'w': + write_table(); /* does not return */ + break; +#if defined(sparc) + case 'y': + if (sun_label) + sun_set_pcylcount(); + break; +#endif + default: + xmenu(); } } } -void try(char *device) +int +is_ide_cdrom(char *device) { + /* No device was given explicitly, and we are trying some + likely things. But opening /dev/hdc may produce errors like + "hdc: tray open or drive not ready" + if it happens to be a CD-ROM drive. It even happens that + the process hangs on the attempt to read a music CD. + So try to be careful. This only works since 2.1.73. */ + + FILE *procf; + char buf[100]; + struct stat statbuf; + + sprintf(buf, "/proc/ide/%s/media", device+5); + procf = fopen(buf, "r"); + if (procf != NULL && fgets(buf, sizeof(buf), procf)) + return !strncmp(buf, "cdrom", 5); + + /* Now when this proc file does not exist, skip the + device when it is read-only. */ + if (stat(device, &statbuf) == 0) + return (statbuf.st_mode & 0222) == 0; + + return 0; +} + +void try(char *device, int user_specified) { disk_device = device; if (!setjmp(listingbuf)) { + if (!user_specified) + if (is_ide_cdrom(device)) + return; if ((fd = open(disk_device, type_open)) >= 0) { - if (get_boot()) { - close(fd); - list_table(); - if (partitions > 4) - delete_partition(ext_index); + if (get_boot(try_only) < 0) { + if (btrydev(device) < 0) + fprintf(stderr, + "Disk doesn't contain a valid " + "partition table\n"); + close(fd); } else { - btrydev(device); - close(fd); + close(fd); + list_table(0); + if (!sun_label && partitions > 4) + delete_partition(ext_index); } } else { /* Ignore other errors, since we try IDE @@ -1375,106 +1732,209 @@ void try(char *device) installed on the system. */ if(errno == EACCES) { fprintf(stderr, "Cannot open %s\n", device); - exit(1); + return; } } } } +void +dummy(int *kk) {} + void main(int argc, char **argv) { - if (argc > 3) - fatal(usage); - if (argc > 1 && *argv[1] == '-') { - switch (*(argv[1] + 1)) { - case 'v': - printf("fdisk v" VERSION "\n"); - exit(0); - case 'l': - listing = 1; - type_open = O_RDONLY; - try("/dev/hda"); - try("/dev/hdb"); - try("/dev/hdc"); - try("/dev/hdd"); - try("/dev/sda"); - try("/dev/sdb"); - try("/dev/sdc"); - try("/dev/sdd"); - try("/dev/sde"); - try("/dev/sdf"); - try("/dev/sdg"); - try("/dev/sdh"); - exit(0); - case 's': { - int i; - if (argc < 3) - fatal(usage); - if (!(i = atoi(argv[2] + 8))) - fatal(usage); - disk_device = (char *) malloc(9); - strncpy(disk_device, argv[2], 8); - if ((fd = open(disk_device, O_RDWR)) >= 0) { - close(fd); - get_boot(); - if (i > partitions) exit(1); - if (part_table[--i]->sys_ind > 10) - printf("%d\n", - part_table[i]->nr_sects / 2); - else exit(1); - exit(0); - } + int i, j, s, c; + int optl = 0, opts = 0; + char *part; + + + /* + * Calls: + * fdisk -v + * fdisk -l [-b] [-u] [device] ... + * fdisk -s [partition] ... + * fdisk [-b] [-u] [device] + */ + while ((c = getopt(argc, argv, "blsuv")) != EOF) { + switch (c) { + case 'b': + show_begin = 1; + break; + case 'l': + optl = 1; + break; + case 's': + opts = 1; + break; + case 'u': + unit_flag = 0; + break; + case 'v': + printf("fdisk v" VERSION "\n"); + exit(0); + default: + fatal(usage); + } } - default: + + if (optl) { + listing = 1; + nowarn = 1; + type_open = O_RDONLY; + if (argc > optind) { + int k; + /* avoid gcc warning: + variable `k' might be clobbered by `longjmp' */ + dummy(&k); + for(k=optind; k= partitions) + exit(1); +#if defined(sparc) + if (!sun_label) { + int id = sunlabel->infos[i].id; + + if (!(id > 1 && id != WHOLE_DISK)) + exit(1); + s = get_num_sectors(sunlabel->partitions[i]); + } else +#endif + s = get_nr_sects(part_table[i]); + if (opts == 1) + printf("%d\n", s/2); + else + printf("%s: %d\n", argv[j], s/2); } + exit(0); } - if (argc > 1) - disk_device = argv[argc - 1]; - else if ((fd = open(DEFAULT_DEVICE, O_RDWR)) < 0) - disk_device = ALTERNATE_DEVICE; - else close(fd); - if (argc == 1) + if (argc-optind == 1) + disk_device = argv[optind]; + else if (argc-optind != 0) + fatal(usage); + else { + if ((fd = open(DEFAULT_DEVICE, O_RDWR)) < 0) + disk_device = ALTERNATE_DEVICE; + else close(fd); printf("Using %s as default device!\n", disk_device); - get_boot(); + } + get_boot(fdisk); while (1) { putchar('\n'); switch (tolower(read_char("Command (m for help): "))) { - case 'a': toggle_active(get_partition(1, partitions)); - break; -/* There should be a define which allows to turn off disklabel support so as - not to make fdisk larger than necessary on installation boot disks. -*/ -#if 1 /* #ifndef NO_DISKLABEL_SUPPORT */ - case 'b': bselect(); /* bf */ - break; + case 'a': +#if defined(sparc) + if (sun_label) + toggle_sunflags(get_partition(1, partitions), + 0x01); + else +#endif + toggle_active(get_partition(1, partitions)); + break; + case 'b': + bselect(); + break; + case 'c': +#if defined(sparc) + if (sun_label) + toggle_sunflags(get_partition(1, partitions), + 0x10); + else #endif - case 'c': toggle_dos(); - break; - case 'd': delete_partition( - get_partition(1, partitions)); - break; - case 'l': list_types(sys_types, nsys_types); /* bf */ - break; - case 'n': new_partition(); - break; - case 'p': list_table(); - break; - case 'q': close(fd); - exit(0); - case 't': change_sysid(); - break; - case 'u': change_units(); - break; - case 'v': verify(); - break; - case 'w': write_table(); - case 'x': xselect(); - break; - default: menu(); + break; + case 'd': + delete_partition( + get_partition(1, partitions)); + break; + case 'l': +#if defined(sparc) + if (sun_label) + list_types(sun_sys_types); + else +#endif + list_types(sys_types); + break; + case 'n': + new_partition(); + break; + case 'o': + create_doslabel(); + break; + case 'p': + list_table(0); + break; + case 'q': + close(fd); + exit(0); +#if defined(sparc) + case 's': + create_sunlabel(); + break; +#endif + case 't': + change_sysid(); + break; + case 'u': + change_units(); + break; + case 'v': + verify(); + break; + case 'w': + write_table(); /* does not return */ + break; + case 'x': + xselect(); + break; + default: menu(); } } } + -- cgit v1.2.3-55-g7522