From 5c36a0eb7cdb0360f9afd5d747c321f423b35984 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 7 Dec 2006 00:25:37 +0100 Subject: Imported from util-linux-2.9i tarball. --- fdisk/fdisk.c | 2046 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2046 insertions(+) create mode 100644 fdisk/fdisk.c (limited to 'fdisk/fdisk.c') diff --git a/fdisk/fdisk.c b/fdisk/fdisk.c new file mode 100644 index 000000000..8cdc6df84 --- /dev/null +++ b/fdisk/fdisk.c @@ -0,0 +1,2046 @@ +/* fdisk.c -- Partition table manipulator for Linux. + * + * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk) + * + * This program is free software. You can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation: either version 1 or + * (at your option) any later version. + * + * Before Linux version 0.95c, this program requires a kernel patch. + * + * Modified, Tue Feb 2 18:46:49 1993, faith@cs.unc.edu to better support SCSI. + * Modified, Sat Feb 27 18:11:27 1993, faith@cs.unc.edu: added extfs support. + * Modified, Sat Mar 6 10:14:12 1993, faith@cs.unc.edu: added more comments. + * Modified, Sat Mar 6 12:25:45 1993, faith@cs.unc.edu: + * Added patches from Michael Bischoff (i1041905@ws.rz.tu-bs.de + * or mbi@mo.math.nat.tu-bs.de) to fix the following problems: + * 1) Incorrect mapping of head/sector/cylinder to absolute sector + * 2) Odd sector count causes one sector to be lost + * Modified, Sat Mar 6 12:25:52 1993, faith@cs.unc.edu: improved verification. + * Modified, Sat Apr 17 15:00:00 1993, LeBlanc@mcc.ac.uk: add -s, fix -l. + * Modified, Sat Apr 24 10:00:00 1993, LeBlanc@mcc.ac.uk: fix overlap bug. + * Modified, Wed May 5 21:30:00 1993, LeBlanc@mcc.ac.uk: errors to stderr. + * Modified, Mon Mar 21 20:00:00 1994, LeBlanc@mcc.ac.uk: + * more stderr for messages, avoid division by 0, and + * give reboot message only if ioctl(fd, BLKRRPART) fails. + * Modified, Mon Apr 25 01:01:05 1994, martin@cs.unc.edu: + * 1) Added support for DOS, OS/2, ... compatibility. We should be able + * use this fdisk to partition our drives for other operating systems. + * 2) Added a print the raw data in the partition table command. + * Modified, Wed Jun 22 21:05:30 1994, faith@cs.unc.edu: + * Added/changed a few partition type names to conform to cfdisk. + * (suggested by Sujal, smpatel@wam.umd.edu) + * Modified 3/5/95 leisner@sdsp.mc.xerox.com -- on -l only open + * devices RDONLY (instead of RDWR). This allows you to + * have the disks as rw-r----- with group disk (and if you + * want is safe to setguid fdisk to disk). + * Modified Sat Mar 11 10:02 1995 with more partition types, faith@cs.unc.edu + * Modified, Thu May 4 01:11:45 1995, esr@snark.thyrsus.com: + * It's user-interface cleanup time. + * Actual error messages for out-of-bounds values (what a concept!). + * Enable read-only access to partition table for learners. + * Smart defaults for most numeric prompts. + * Fixed a bug preventing a partition from crossing cylinder 8064, aeb, 950801. + * Read partition table twice to avoid kernel bug + * (from Daniel Quinlan ), Tue Sep 26 10:25:28 1995 + * Modified, Sat Jul 1 23:43:16 MET DST 1995, fasten@cs.bonn.edu: + * editor for NetBSD/i386 (and Linux/Alpha?) disklabels. + * 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. + * Fixed for using variable blocksizes (needed by magnet-optical drive-patch) + * (from orschaer@cip.informatik.uni-erlangen.de) + * 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. + * Modified, Sat Oct 3 14:40:17 MET DST 1998, ANeuper@GUUG.de + * Support SGI's partitioning -- an, 980930. + * Do the verify using LBA, not CHS, limits -- aeb, 981206. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include /* for HDIO_GETGEO */ +#include /* for BLKRRPART, BLKGETSIZE */ + +#include "fdisk.h" + +#include "fdisksunlabel.h" +#include "fdisksgilabel.h" +#include "fdiskaixlabel.h" + +#include "../version.h" + +#define hex_val(c) ({ \ + char _c = (c); \ + isdigit(_c) ? _c - '0' : \ + tolower(_c) + 10 - 'a'; \ + }) + + +#define DEFAULT_DEVICE "/dev/hda" +#define ALTERNATE_DEVICE "/dev/sda" +#define LINE_LENGTH 80 +#define offset(b, n) ((struct partition *)((b) + 0x1be + \ + (n) * sizeof(struct partition))) +#define sector(s) ((s) & 0x3f) +#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2)) + +#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \ + ((h) + heads * cylinder(s,c))) +#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; \ + } + +/* 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); +} + +/* normally O_RDWR, -l option gives O_RDONLY */ +static int type_open = O_RDWR; + +char *disk_device = DEFAULT_DEVICE, /* hda, unless specified */ + *line_ptr, /* interactive input */ + line_buffer[LINE_LENGTH], + changed[MAXIMUM_PARTS], /* marks changed buffers */ + buffer[MAX_SECTOR_SIZE], /* first four partitions */ + *buffers[MAXIMUM_PARTS] /* pointers to buffers */ + = {buffer, buffer, buffer, buffer}; + +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 */ + dos_compatible_flag = ~0, + partitions = 4; /* maximum partition + 1 */ + +uint heads, + sectors, + cylinders, + sector_size = DEFAULT_SECTOR_SIZE, + sector_offset = 1, + display_factor = 1, /* in units/sector */ + unit_flag = 1, + extended_offset = 0, /* offset of link pointers */ + offsets[MAXIMUM_PARTS] = {0, 0, 0, 0}; + +int sun_label = 0; /* looking at sun disklabel */ +int sgi_label = 0; /* looking at sgi disklabel */ +int aix_label = 0; /* looking at aix 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[] = { + {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)"}, + {0x11, "Hidden DOS FAT12"}, + {0x14, "Hidden DOS FAT16"}, + {0x16, "Hidden DOS FAT16 (big)"}, + {0x17, "Hidden OS/2 HPFS or NTFS"}, + {0x40, "Venix 80286"}, + {0x41, "PPC PReP Boot"}, + {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"}, + {0xeb, "BeOS fs"}, + {0xf2, "DOS secondary"}, + {0xff, "BBT"}, /* (bad track table) */ + { 0, NULL } +}; + +jmp_buf listingbuf; + +void fatal(enum failure why) +{ + char error[LINE_LENGTH], + *message = error; + + if (listing) { + close(fd); + longjmp(listingbuf, 1); + } + + switch (why) { + case usage: message = +"Usage: fdisk [-b SSZ] [-u] [DISK] Change partition table\n" +" fdisk -l [-b SSZ] [-u] [DISK] List partition table(s)\n" +" fdisk -s PARTITION Give partition size(s) in blocks\n" +" fdisk -v Give fdisk version\n" +"Here DISK is something like /dev/hdb or /dev/sda\n" +"and PARTITION is something like /dev/hda7\n" +"-u: give Start and End in sector (instead of cylinder) units\n" +"-b 2048: (for certain MO drives) use 2048-byte sectors\n"; + break; + case no_device: + message = "A disk block device is needed.\n"; + break; + case no_partition: + message = "Given name does not refer to a partition,\n" + "or maybe not even to a block device.\n"; + break; + case unable_to_open: + sprintf(error, "Unable to open %s\n", disk_device); + break; + case unable_to_read: + sprintf(error, "Unable to read %s\n", disk_device); + break; + case unable_to_seek: + sprintf(error, "Unable to seek on %s\n", disk_device); + break; + case unable_to_write: + sprintf(error, "Unable to write %s\n", disk_device); + break; + case out_of_memory: + message = "Unable to allocate any more memory\n"; + break; + default: message = "Fatal error\n"; + } + + fputc('\n', stderr); + fputs(message, stderr); + exit(1); +} + +void menu(void) +{ + 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 if(sgi_label) + puts("Command action\n" + " a select bootable partition\n" /* sgi flavour */ + " b edit bootfile entry\n" /* sgi */ + " c select sgi swap partition\n" /* sgi flavour */ + " 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" + " u change display/entry units\n" + " v verify the partition table\n" + " w write table to disk and exit\n" + ); + else if(aix_label) + puts("Command action\n" + " m print this menu\n" + " o create a new empty DOS partition table\n" + " q quit without saving changes\n" + ); + else + puts("Command action\n" + " a toggle a bootable flag\n" + " 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" + " 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)" + ); +} + +void xmenu(void) +{ + 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" /* !sun */ + " g create an IRIX partition table\n" /* sgi */ + " h change number of heads\n" + " 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" + ); +} + +int +get_sysid(int i) { + return ( + sun_label ? sunlabel->infos[i].id : + sgi_label ? sgi_get_sysid(i) : part_table[i]->sys_ind); +} + +struct systypes * +get_sys_types(void) { + return ( + sun_label ? sun_sys_types : + sgi_label ? sgi_sys_types : sys_types); +} + +char *partition_type(unsigned char type) +{ + int i; + struct systypes *types = get_sys_types(); + + for (i=0; types[i].name; i++) + if (types[i].index == type) + return types[i].name; + + return NULL; +} + +void list_types(struct systypes *sys) +{ + 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; + + do { + printf("%c%2x %-15.15s", i ? ' ' : '\n', + sys[next].index, sys[next].name); + next = last[i++] + done; + if (i > 3 || next >= last[i]) { + i = 0; + next = ++done; + } + } while (done < last[0]); + putchar('\n'); +} + +void clear_partition(struct partition *p) +{ + p->boot_ind = 0; + p->head = 0; + p->sector = 0; + p->cyl = 0; + p->sys_ind = 0; + p->end_head = 0; + p->end_sector = 0; + p->end_cyl = 0; + set_start_sect(p,0); + set_nr_sects(p,0); +} + +void set_partition(int i, struct partition *p, uint start, uint stop, + int sysid, uint offset) +{ + p->boot_ind = 0; + 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); + if (dos_compatible_flag && (stop/(sectors*heads) > 1023)) + stop = heads*sectors*1024 - 1; + set_hsc(p->end_head, p->end_sector, p->end_cyl, stop); + changed[i] = 1; +} + +int test_c(char **m, char *mesg) +{ + int val = 0; + if (!*m) + fprintf(stderr, "You must set"); + else { + fprintf(stderr, " %s", *m); + val = 1; + } + *m = mesg; + return val; +} + +int warn_geometry(void) +{ + char *m = NULL; + int prev = 0; + if (!heads) + prev = test_c(&m, "heads"); + if (!sectors) + prev = test_c(&m, "sectors"); + if (!cylinders) + prev = test_c(&m, "cylinders"); + if (!m) + return 0; + fprintf(stderr, + "%s%s.\nYou can do this from the extra functions menu.\n", + prev ? " and " : " ", m); + return 1; +} + +void update_units(void) +{ + int cyl_units = heads * sectors; + + if (unit_flag && cyl_units) + display_factor = cyl_units; + else + display_factor = 1; /* in sectors */ +} + +void warn_cylinders(void) +{ + if (!sun_label && !sgi_label && cylinders > 1024 && !nowarn) + fprintf(stderr, "\n\ +The number of cylinders for this disk is set to %d.\n\ +There is nothing wrong with that, but this is larger than 1024,\n\ +and could in certain setups cause problems with:\n\ +1) software that runs at boot time (e.g., LILO)\n\ +2) booting and partitioning software from other OSs\n\ + (e.g., DOS FDISK, OS/2 FDISK)\n", + cylinders); +} + +void read_extended(struct partition *p) +{ + int i; + struct partition *q; + + ext_pointers[ext_index] = part_table[ext_index]; + if (!get_start_sect(p)) + fprintf(stderr, "Bad offset in primary extended partition\n"); + else while (IS_EXTENDED (p->sys_ind)) { + if (partitions >= MAXIMUM_PARTS) { + fprintf(stderr, + "Warning: deleting partitions after %d\n", + partitions); + clear_partition(ext_pointers[partitions - 1]); + changed[partitions - 1] = 1; + return; + } + offsets[partitions] = extended_offset + get_start_sect(p); + if (!extended_offset) + extended_offset = get_start_sect(p); + if (ext2_llseek(fd, (ext2_loff_t)offsets[partitions] + * sector_size, SEEK_SET) < 0) + fatal(unable_to_seek); + if (!(buffers[partitions] = (char *) malloc(sector_size))) + fatal(out_of_memory); + if (sector_size != read(fd, buffers[partitions], sector_size)) + fatal(unable_to_read); + part_table[partitions] = ext_pointers[partitions] = NULL; + q = p = offset(buffers[partitions], 0); + for (i = 0; i < 4; i++, p++) { + if (IS_EXTENDED (p->sys_ind)) { + if (ext_pointers[partitions]) + fprintf(stderr, "Warning: extra link " + "pointer in partition table " + "%d\n", partitions + 1); + else + ext_pointers[partitions] = p; + } else if (p->sys_ind) { + if (part_table[partitions]) + fprintf(stderr, + "Warning: ignoring extra data " + "in partition table %d\n", + partitions + 1); + else + part_table[partitions] = p; + } + } + if (!part_table[partitions]) { + if (q != ext_pointers[partitions]) + part_table[partitions] = q; + else part_table[partitions] = q + 1; + } + if (!ext_pointers[partitions]) { + if (q != part_table[partitions]) + ext_pointers[partitions] = q; + else ext_pointers[partitions] = q + 1; + } + p = ext_pointers[partitions++]; + } +} + +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"); + + sun_nolabel(); /* otherwise always recognised as sun */ + sgi_nolabel(); /* otherwise always recognised as sgi */ + + 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, sec_fac; + struct hd_geometry geometry; + + partitions = 4; + sec_fac = sector_size / 512; + + 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"); + } + + guess_device_type(fd); + + if (sector_size != read(fd, buffer, sector_size)) + fatal(unable_to_read); + +#ifdef HDIO_REQ + if (!ioctl(fd, HDIO_REQ, &geometry)) { +#else + if (!ioctl(fd, HDIO_GETGEO, &geometry)) { +#endif + heads = geometry.heads; + sectors = geometry.sectors; + cylinders = geometry.cylinders; + cylinders /= sec_fac; /* do not round up */ + if (dos_compatible_flag) + sector_offset = sectors; + } else { + if (!ioctl(fd, BLKGETSIZE, §ors)) { + heads = 1; + cylinders = 1; + sectors /= sec_fac; + } else { + heads = cylinders = sectors = 0; + } + } + update_units(); + +got_table: + + if (check_sun_label()) + return 0; + + if (check_sgi_label()) + return 0; + + if (check_aix_label()) + return 0; + + if (!valid_part_table_flag(buffer)) { + switch(what) { + case fdisk: + fprintf(stderr, + "Device contains neither a valid DOS partition" + " table, nor Sun or SGI 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(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 (!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 0; +} + +/* read line; return 0 or first char */ +int +read_line(void) +{ + line_ptr = line_buffer; + if (!fgets(line_buffer, LINE_LENGTH, stdin)) + return 0; + while (*line_ptr && !isgraph(*line_ptr)) + line_ptr++; + return *line_ptr; +} + +char +read_char(char *mesg) +{ + do { + fputs(mesg, stdout); + } while (!read_line()); + return *line_ptr; +} + +char +read_chars(char *mesg) +{ + fputs(mesg, stdout); + if (!read_line()) { + *line_ptr = '\n'; + line_ptr[1] = 0; + } + return *line_ptr; +} + +int +read_hex(struct systypes *sys) +{ + int hex; + + while (1) + { + read_char("Hex code (type L to list codes): "); + if (tolower(*line_ptr) == 'l') + list_types(sys); + else if (isxdigit (*line_ptr)) + { + hex = 0; + do + hex = hex << 4 | hex_val(*line_ptr++); + while (isxdigit(*line_ptr)); + return hex; + } + } +} + +/* + * Print the message MESG, then read an integer between LOW and HIGH. + * If the user hits Enter, DFLT is returned. + * Answers like +10 are interpreted as offsets from BASE. + * + * There is no default if DFLT is not between LOW and HIGH. + */ +uint +read_int(uint low, uint dflt, uint high, uint base, char *mesg) +{ + uint i; + int default_ok = 1; + static char *ms = NULL; + static int mslen = 0; + + if (!ms || strlen(mesg)+50 > mslen) { + mslen = strlen(mesg)+100; + if (!(ms = realloc(ms,mslen))) + fatal(out_of_memory); + } + + if (dflt < low || dflt > high) + default_ok = 0; + + if (default_ok) + sprintf(ms, "%s (%d-%d, default %d): ", mesg, low, high, dflt); + else + sprintf(ms, "%s (%d-%d): ", mesg, low, high); + + while (1) { + int use_default = default_ok; + + /* ask question and read answer */ + while (read_chars(ms) != '\n' && !isdigit(*line_ptr) + && *line_ptr != '-' && *line_ptr != '+') + continue; + + if (*line_ptr == '+' || *line_ptr == '-') { + i = atoi(line_ptr+1); + if (*line_ptr == '-') + i = -i; + while (isdigit(*++line_ptr)) + use_default = 0; + switch (*line_ptr) { + case 'c': + case 'C': + if (!unit_flag) + i *= heads * sectors; + break; + case 'k': + case 'K': + i *= 2; + i /= (sector_size / 512); + i /= display_factor; + break; + case 'm': + case 'M': + i *= 2048; + i /= (sector_size / 512); + i /= display_factor; + break; + case 'g': + case 'G': + i *= 2048000; + i /= (sector_size / 512); + i /= display_factor; + break; + default: + break; + } + i += base; + } else { + i = atoi(line_ptr); + while (isdigit(*line_ptr)) { + line_ptr++; + use_default = 0; + } + } + if (use_default) + printf("Using default value %d\n", i = dflt); + if (i >= low && i <= high) + break; + else + printf("Value out of range.\n"); + } + return i; +} + +int get_partition(int warn, int max) +{ + int i = read_int(1, 0, max, 0, "Partition number") - 1; + + if (warn && ( + (!sun_label && !sgi_label && !part_table[i]->sys_ind) + || (sun_label && + (!sunlabel->partitions[i].num_sectors || + !sunlabel->infos[i].id)) + || (sgi_label && (!sgi_get_num_sectors(i))) + )) fprintf(stderr, "Warning: partition %d has empty type\n", i+1); + return i; +} + +char *const str_units(void) +{ + return unit_flag ? "cylinder" : "sector"; +} + +void change_units(void) +{ + if ((unit_flag = !unit_flag)) + display_factor = 1; + else display_factor = heads * sectors; + update_units(); + printf("Changing display/entry units to %ss\n", + str_units()); +} + +void toggle_active(int i) +{ + struct partition *p = part_table[i]; + + if (IS_EXTENDED (p->sys_ind) && !p->boot_ind) + fprintf(stderr, + "WARNING: Partition %d is an extended partition\n", + i + 1); + if (p->boot_ind) + p->boot_ind = 0; + else p->boot_ind = ACTIVE_FLAG; + changed[i] = 1; +} + +void toggle_dos(void) +{ + dos_compatible_flag = ~dos_compatible_flag; + printf("DOS Compatibility flag is "); + if (dos_compatible_flag) + sector_offset = sectors; + else { + sector_offset = 1; + printf("not "); + } + printf("set\n"); +} + +void delete_partition(int i) +{ + struct partition *p = part_table[i], *q = ext_pointers[i]; + +/* Note that for the fifth partition (i == 4) we don't actually + * decrement partitions. + */ + + if (warn_geometry()) + return; + changed[i] = 1; + + if (sun_label) { + sun_delete_partition(i); + return; + } + if (sgi_label) { + sgi_delete_partition(i); + return; + } + if (i < 4) { + if (IS_EXTENDED (p->sys_ind) && i == ext_index) { + while (partitions > 4) + free(buffers[--partitions]); + ext_pointers[ext_index] = NULL; + extended_offset = 0; + } + clear_partition(p); + } + else if (!q->sys_ind && i > 4) { + free(buffers[--partitions]); + clear_partition(ext_pointers[--i]); + } + else if (i > 3) { + if (i > 4) { + p = ext_pointers[i - 1]; + p->boot_ind = 0; + p->head = q->head; + p->sector = q->sector; + p->cyl = q->cyl; + p->sys_ind = EXTENDED; + p->end_head = q->end_head; + p->end_sector = q->end_sector; + p->end_cyl = q->end_cyl; + 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 */ + set_start_sect(part_table[5], + get_start_sect(part_table[5]) + + offsets[5] - extended_offset); + offsets[5] = extended_offset; + changed[5] = 1; + } + if (partitions > 5) { + partitions--; + free(buffers[i]); + while (i < partitions) { + changed[i] = changed[i + 1]; + buffers[i] = buffers[i + 1]; + offsets[i] = offsets[i + 1]; + part_table[i] = part_table[i + 1]; + ext_pointers[i] = ext_pointers[i + 1]; + i++; + } + } + else + clear_partition(part_table[i]); + } +} + +void change_sysid(void) +{ + char *temp; + int i = get_partition(0, partitions), sys, origsys; + struct partition *p = part_table[i]; + + origsys = sys = get_sysid(i); + + if (!sys && !sgi_label) + printf("Partition %d does not exist yet!\n", i + 1); + else while (1) { + sys = read_hex (get_sys_types()); + + if (!sys && !sgi_label) { + printf("Type 0 means free space to many systems\n" + "(but not to Linux). Having partitions of\n" + "type 0 is probably unwise. You can delete\n" + "a partition using the `d' command.\n"); + /* break; */ + } + + if (!sun_label && !sgi_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 (sys < 256) { + 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\n"); + if (sgi_label && ((i == 10 && sys != ENTIRE_DISK) + || (i == 8 && sys != 0))) + printf("Consider leaving partition 9 " + "as volume header (0),\nand " + "partition 11 as entire volume (6)" + "as IRIX expects it.\n\n"); + if (sys == origsys) + break; + + if (sun_label) { + sun_change_sysid(i, sys); + } else + if (sgi_label) { + sgi_change_sysid(i, sys); + } else + 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, + * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross, + * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S. + * Lubkin Oct. 1991). */ + +static void long2chs(ulong ls, uint *c, uint *h, uint *s) +{ + int spc = heads * sectors; + + *c = ls / spc; + ls = ls % spc; + *h = ls / sectors; + *s = ls % sectors + 1; /* sectors count from 1 */ +} + +static void check_consistency(struct partition *p, int partition) +{ + uint pbc, pbh, pbs; /* physical beginning c, h, s */ + uint pec, peh, pes; /* physical ending c, h, s */ + uint lbc, lbh, lbs; /* logical beginning c, h, s */ + uint lec, leh, les; /* logical ending c, h, s */ + + if (!heads || !sectors || (partition >= 4)) + return; /* do not check extended partitions */ + +/* physical beginning c, h, s */ + pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300); + pbh = p->head; + pbs = p->sector & 0x3f; + +/* physical ending c, h, s */ + pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300); + peh = p->end_head; + pes = p->end_sector & 0x3f; + +/* compute logical beginning (c, h, s) */ + long2chs(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); + +/* Same physical / logical beginning? */ + if (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); + printf("logical=(%d, %d, %d)\n",lbc, lbh, lbs); + } + +/* Same physical / logical ending? */ + if (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); + printf("logical=(%d, %d, %d)\n",lec, leh, les); + } + +#if 0 +/* Beginning on cylinder boundary? */ + if (pbh != !pbc || pbs != 1) { + printf("Partition %i does not start on cylinder " + "boundary:\n", partition + 1); + printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs); + printf("should be (%d, %d, 1)\n", pbc, !pbc); + } +#endif + +/* Ending on cylinder boundary? */ + if (peh != (heads - 1) || pes != sectors) { + printf("Partition %i does not end on cylinder boundary:\n", + partition + 1); + printf(" phys=(%d, %d, %d) ", pec, peh, pes); + printf("should be (%d, %d, %d)\n", + pec, heads - 1, sectors); + } +} + +void list_disk_geometry(void) +{ + printf("\nDisk %s: %d heads, %d sectors, %d cylinders\nUnits = " + "%ss of %d * %d bytes\n\n", disk_device, heads, sectors, + cylinders, str_units(), display_factor, sector_size); +} + +void list_table(int xtra) +{ + struct partition *p; + char *type; + int digit_last = 0; + int i, w; + + if (sun_label) { + sun_list_table(xtra); + return; + } + + if (sgi_label) { + sgi_list_table(xtra); + return; + } + + w = strlen(disk_device); + /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3, + but if the device name ends in a digit, say /dev/foo1, + then the partition is called /dev/foo1p3. */ + if (isdigit(disk_device[w-1])) + digit_last = 1; + + list_disk_geometry(); + + if (w < 5) + w = 5; + printf("%*s Boot Start End Blocks Id System\n", + (digit_last ? w + 2 : w + 1), "Device"); + + for (i = 0 ; i < partitions; i++) { + if ((p = part_table[i])->sys_ind) { + unsigned int psects = get_nr_sects(p); + unsigned int pblocks = psects; + unsigned int podd = 0; + + if (sector_size < 1024) { + pblocks /= (1024 / sector_size); + podd = psects % (1024 / sector_size); + } + if (sector_size > 1024) + pblocks *= (sector_size / 1024); + printf( + "%*s%s%-2d %c %9ld %9ld %9ld%c %2x %s\n", +/* device */ w, disk_device, (digit_last ? "p" : ""), i+1, +/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG + ? '*' : '?', +/* start */ (long) cround(get_start_sect(p) + offsets[i]), +/* end */ (long) cround(get_start_sect(p) + offsets[i] + psects + - (psects ? 1 : 0)), +/* odd flag on end */ (long) pblocks, podd ? '+' : ' ', +/* 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) +{ + struct partition *p, **q; + int i; + + if (extend) + q = ext_pointers; + else + q = part_table; + printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n", + disk_device, heads, sectors, cylinders); + printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"); + for (i = 0 ; i < partitions; i++) + if ((p = q[i]) != NULL) { + printf("%2d %02x%4d%4d%5d%4d%4d%5d%8d%8d %02x\n", + i + 1, p->boot_ind, p->head, + sector(p->sector), + cylinder(p->sector, p->cyl), p->end_head, + sector(p->end_sector), + cylinder(p->end_sector, p->end_cyl), + get_start_sect(p), get_nr_sects(p), p->sys_ind); + if (p->sys_ind) + check_consistency(p, i); + } +} + +void fill_bounds(uint *first, uint *last) +{ + int i; + struct partition *p = part_table[0]; + + for (i = 0; i < partitions; p = part_table[++i]) { + if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) { + first[i] = 0xffffffff; + last[i] = 0; + } else { + first[i] = get_start_sect(p) + offsets[i]; + last[i] = first[i] + get_nr_sects(p) - 1; + } + } +} + +void check(int n, uint h, uint s, uint c, uint start) +{ + uint total, real_s, real_c; + + real_s = sector(s) - 1; + real_c = cylinder(s, c); + total = (real_c * sectors + real_s) * heads + h; + if (!total) + fprintf(stderr, "Warning: partition %d contains sector 0\n", n); + if (h >= heads) + fprintf(stderr, + "Partition %d: head %d greater than maximum %d\n", + n, h + 1, heads); + if (real_s >= sectors) + fprintf(stderr, "Partition %d: sector %d greater than " + "maximum %d\n", n, s, sectors); + if (real_c >= cylinders) + fprintf(stderr, "Partitions %d: cylinder %d greater than " + "maximum %d\n", n, real_c + 1, cylinders); + if (cylinders <= 1024 && start != total) + fprintf(stderr, + "Partition %d: previous sectors %d disagrees with " + "total %d\n", n, start, total); +} + + +void verify(void) +{ + int i, j; + uint total = 1; + uint first[partitions], last[partitions]; + struct partition *p = part_table[0]; + + if (warn_geometry()) + return; + + if (sun_label) { + verify_sun(); + return; + } + + if (sgi_label) { + verify_sgi(1); + return; + } + + fill_bounds(first, last); + for (i = 0; i < partitions; p = part_table[++i]) + if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) { + check_consistency(p, 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, + last[i]); + total += last[i] + 1 - first[i]; + for (j = 0; j < i; j++) + if ((first[i] >= first[j] && first[i] <= last[j]) + || ((last[i] <= last[j] && last[i] >= first[j]))) { + printf("Warning: partition %d overlaps " + "partition %d.\n", j + 1, i + 1); + total += first[i] >= first[j] ? + first[i] : first[j]; + total -= last[i] <= last[j] ? + last[i] : last[j]; + } + } + + if (extended_offset) { + 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]) { + total++; + if (!p->sys_ind) { + if (i != 4 || i + 1 < partitions) + printf("Warning: partition %d " + "is empty\n", i + 1); + } + else if (first[i] < extended_offset || + last[i] > e_last) + printf("Logical partition %d not entirely in " + "partition %d\n", i + 1, ext_index + 1); + } + } + + if (total > heads * sectors * cylinders) + printf("Total allocated sectors %d greater than the maximum " + "%d\n", total, heads * sectors * cylinders); + else if ((total = heads * sectors * cylinders - total) != 0) + printf("%d unallocated sectors\n", total); +} + +void add_partition(int n, int sys) +{ + char mesg[48]; + int i, read = 0; + struct partition *p = part_table[n], *q = part_table[ext_index]; + uint start, stop = 0, limit, temp, + first[partitions], last[partitions]; + + if (p->sys_ind) { + printf("Partition %d is already defined. Delete " + "it before re-adding it.\n", n + 1); + return; + } + fill_bounds(first, last); + if (n < 4) { + start = sector_offset; + limit = heads * sectors * cylinders - 1; + if (extended_offset) { + first[ext_index] = extended_offset; + last[ext_index] = get_start_sect(q) + + get_nr_sects(q) - 1; + } + } else { + start = extended_offset + sector_offset; + limit = get_start_sect(q) + get_nr_sects(q) - 1; + } + if (unit_flag) + for (i = 0; i < partitions; i++) + first[i] = (cround(first[i]) - 1) * display_factor; + + sprintf(mesg, "First %s", str_units()); + do { + temp = start; + for (i = 0; i < partitions; i++) { + int lastplusoff; + + if (start == offsets[i]) + start += 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+display_factor && read) { + printf("Sector %d is already allocated\n", temp); + temp = start; + read = 0; + } + if (!read && start == temp) { + uint i; + i = start; + start = read_int(cround(i), cround(i), cround(limit), + 0, mesg); + if (unit_flag) { + start = (start - 1) * display_factor; + if (start < i) start = i; + } + read = 1; + } + } while (start != temp || !read); + if (n > 4) /* NOT for fifth partition */ + offsets[n] = start - sector_offset; + + for (i = 0; i < partitions; i++) { + if (start < offsets[i] && limit >= offsets[i]) + limit = offsets[i] - 1; + if (start < first[i] && limit >= first[i]) + limit = first[i] - 1; + } + if (start > limit) { + printf("No free sectors available\n"); + if (n > 4) { + free(buffers[n]); + partitions--; + } + return; + } + if (cround(start) == cround(limit)) + stop = start; + else { + sprintf(mesg, "Last %s or +size or +sizeM or +sizeK", + str_units()); + stop = read_int(cround(start), cround(limit), cround(limit), + cround(start), mesg); + if (unit_flag) { + stop = stop * display_factor - 1; + if (stop >limit) + stop = limit; + } + } + + set_partition(n, p, start, stop, sys, offsets[n]); + + if (IS_EXTENDED (sys)) { + ext_index = n; + offsets[4] = extended_offset = start; + ext_pointers[n] = p; + if (!(buffers[4] = calloc(1, sector_size))) + fatal(out_of_memory); + part_table[4] = offset(buffers[4], 0); + ext_pointers[4] = part_table[4] + 1; + changed[4] = 1; + partitions = 5; + } + else { + if (n > 4) + set_partition(n - 1, ext_pointers[n - 1], + start - sector_offset, stop, EXTENDED, + extended_offset); +#if 0 + if ((limit = get_nr_sects(p)) & 1) + printf("Warning: partition %d has an odd " + "number of sectors.\n", n + 1); +#endif + } +} + +void add_logical(void) +{ + if (partitions > 5 || part_table[4]->sys_ind) { + if (!(buffers[partitions] = calloc(1, sector_size))) + fatal(out_of_memory); + part_table[partitions] = offset(buffers[partitions], 0); + ext_pointers[partitions] = part_table[partitions] + 1; + offsets[partitions] = 0; + partitions++; + } + add_partition(partitions - 1, LINUX_NATIVE); +} + +void new_partition(void) +{ + int i, free_primary = 0; + + if (warn_geometry()) + return; + + if (sun_label) { + add_sun_partition(get_partition(0, partitions), LINUX_NATIVE); + return; + } + + if (sgi_label) { + sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE); + return; + } + + if (partitions >= MAXIMUM_PARTS) { + printf("The maximum number of partitions has been created\n"); + return; + } + + for (i = 0; i < 4; i++) + free_primary += !part_table[i]->sys_ind; + if (!free_primary) { + if (extended_offset) + add_logical(); + else + printf("You must delete some partition and add " + "an extended partition first\n"); + } else { + char c, line[LINE_LENGTH]; + sprintf(line, "Command action\n %s\n p primary " + "partition (1-4)\n", extended_offset ? + "l logical (5 or over)" : "e extended"); + while (1) + if ((c = tolower(read_char(line))) == 'p') { + add_partition(get_partition(0, 4), + LINUX_NATIVE); + return; + } + else if (c == 'l' && extended_offset) { + add_logical(); + return; + } + else if (c == 'e' && !extended_offset) { + add_partition(get_partition(0, 4), + EXTENDED); + return; + } + else + printf("Invalid partition number " + "for type `%c'\n", c); + + } +} + +void write_table(void) +{ + int i, error = 0; + + changed[3] = changed[0] || changed[1] || changed[2] || changed[3]; + if (!sun_label && !sgi_label) { + for (i = 3; i < partitions; i++) { + if (changed[i]) { + 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 (sgi_label) { + /* no test on change? the printf below might be mistaken */ + sgi_write_table(); + } else if (sun_label) { + if (changed[3] || changed[4] || changed[5] || + changed[6] || changed[7]) { + sun_write_table(); + } + } + + printf("The partition table has been altered!\n\n"); + + printf("Calling ioctl() to re-read partition table.\n"); + sync(); + sleep(2); + if ((i = ioctl(fd, BLKRRPART)) != 0) { + error = errno; + } else { + /* some kernel versions (1.2.x) seem to have trouble + rereading the partition table, but if asked to do it + twice, the second time works. - biro@yggdrasil.com */ + sync(); + sleep(2); + if((i = ioctl(fd, BLKRRPART)) != 0) + error = errno; + } + + close(fd); + + printf("Syncing disks.\n"); + sync(); + sleep(4); /* for sync() */ + + if (i < 0) + printf("Re-read table failed with error %d: %s.\nReboot your " + "system to ensure the partition table is updated.\n", + error, strerror(error)); + + if (!sun_label && !sgi_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"); + + exit(0); +} + +#define MAX_PER_LINE 16 +void print_buffer(char buffer[]) +{ + int i, + l; + + for (i = 0, l = 0; i < sector_size; i++, l++) { + if (l == 0) + printf("0x%03X:", i); + printf(" %02X", (unsigned char) buffer[i]); + if (l == MAX_PER_LINE - 1) { + printf("\n"); + l = -1; + } + } + if (l > 0) + printf("\n"); + printf("\n"); +} + +void print_raw(void) +{ + int i; + + printf("Device: %s\n", disk_device); + if (sun_label || sgi_label) + print_buffer(buffer); + else for (i = 3; i < partitions; i++) + print_buffer(buffers[i]); +} + +void move_begin(int i) +{ + struct partition *p = part_table[i]; + uint new, first; + + if (warn_geometry()) + return; + 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 = get_start_sect(p) + offsets[i]; + new = read_int(first, first, + get_start_sect(p) + get_nr_sects(p) + offsets[i] - 1, + first, "New beginning of data") - offsets[i]; + + 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; + } +} + +void xselect(void) +{ + while(1) { + putchar('\n'); + switch (tolower(read_char("Expert command (m for help): "))) { + case 'a': + if (sun_label) + sun_set_alt_cyl(); + break; + case 'b': + if (!sun_label && !sgi_label) + move_begin(get_partition(0, partitions)); + break; + case 'c': + cylinders = read_int(1, cylinders, 65535, + 0, "Number of cylinders"); + if (sun_label) + sun_set_ncyl(cylinders); + warn_cylinders(); + break; + case 'd': + print_raw(); + break; + case 'e': + if (sgi_label) + sgi_set_xcyl(); + else if (sun_label) + sun_set_xcyl(); + else + x_list_table(1); + break; + case 'g': + create_sgilabel(); + break; + case 'h': + heads = read_int(1, heads, 256, 0, + "Number of heads"); + update_units(); + break; + case 'i': + if (sun_label) + sun_set_ilfact(); + break; + case 'o': + if (sun_label) + sun_set_rspeed(); + break; + case 'p': + if (sun_label) + list_table(1); + else + x_list_table(0); + break; + case 'q': + close(fd); + exit(0); + case 'r': + return; + case 's': + sectors = read_int(1, sectors, 63, 0, + "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; + case 'y': + if (sun_label) + sun_set_pcylcount(); + break; + default: + xmenu(); + } + } +} + +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; + + if (strncmp("/dev/hd", device, 7)) + return 0; + 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(try_only) < 0) { + list_disk_geometry(); + if (btrydev(device) < 0) + fprintf(stderr, + "Disk %s doesn't contain a valid " + "partition table\n", device); + close(fd); + } else { + close(fd); + list_table(0); + if (!sun_label && partitions > 4) + delete_partition(ext_index); + } + } else { + /* Ignore other errors, since we try IDE + and SCSI hard disks which may not be + installed on the system. */ + if(errno == EACCES) { + fprintf(stderr, "Cannot open %s\n", device); + return; + } + } + } +} + +void +dummy(int *kk) {} + +int +main(int argc, char **argv) +{ + int i, j, s, c; + int optl = 0, opts = 0; + char *part; + + + /* + * Calls: + * fdisk -v + * fdisk -l [-b sectorsize] [-u] [device] ... + * fdisk -s [partition] ... + * fdisk [-b sectorsize] [-u] [device] + */ + while ((c = getopt(argc, argv, "b:lsuv")) != EOF) { + switch (c) { + case 'b': + sector_size = atoi(optarg); + if (sector_size != 512 && sector_size != 1024 && + sector_size != 2048) + fatal(usage); + sector_offset = 2; + break; + case 'l': + optl = 1; + break; + case 's': + opts = 1; + break; + case 'u': + unit_flag = 0; + break; + case 'v': + printf("fdisk v" UTIL_LINUX_VERSION "\n"); + exit(0); + default: + fatal(usage); + } + } + + 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-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(fdisk); + + while (1) { + putchar('\n'); + switch (tolower(read_char("Command (m for help): "))) { + case 'a': + if (sun_label) + toggle_sunflags(get_partition(1, partitions), + 0x01); + else + if (sgi_label) + sgi_set_bootpartition( + get_partition(1, partitions)); + else + toggle_active(get_partition(1, partitions)); + break; + case 'b': + if (sgi_label) { + printf("\nThe current boot file is: %s\n", + sgi_get_bootfile()); + if (read_chars("Please enter the name of the " + "new boot file: ") == '\n') + printf("Boot file unchanged\n"); + else + sgi_set_bootfile(line_ptr); + } else + bselect(); + break; + case 'c': + if (sun_label) + toggle_sunflags(get_partition(1, partitions), + 0x10); + else + if (sgi_label) + sgi_set_swappartition( + get_partition(1, partitions)); + else + toggle_dos(); + break; + case 'd': + delete_partition( + get_partition(1, partitions)); + break; + case 'i': + if (sgi_label) + create_sgiinfo(); + else + menu(); + case 'l': + list_types(get_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); + case 's': + create_sunlabel(); + break; + case 't': + change_sysid(); + break; + case 'u': + change_units(); + break; + case 'v': + verify(); + break; + case 'w': + write_table(); /* does not return */ + break; + case 'x': + if( sgi_label ) { + fprintf(stderr, + "\n\tSorry, no experts menu for SGI " + "partition tables available.\n\n"); + } else + xselect(); + break; + default: menu(); + } + } + return 0; +} -- cgit v1.2.3-55-g7522