diff options
author | Karel Zak | 2006-12-07 00:25:34 +0100 |
---|---|---|
committer | Karel Zak | 2006-12-07 00:25:34 +0100 |
commit | fd6b7a7ffc50400704beb41d5a23af5f9edb1eed (patch) | |
tree | 997c0ca2abc018369babd7da59bcd0afe492068e /disk-utils | |
parent | Imported from util-linux-2.5 tarball. (diff) | |
download | kernel-qcow2-util-linux-fd6b7a7ffc50400704beb41d5a23af5f9edb1eed.tar.gz kernel-qcow2-util-linux-fd6b7a7ffc50400704beb41d5a23af5f9edb1eed.tar.xz kernel-qcow2-util-linux-fd6b7a7ffc50400704beb41d5a23af5f9edb1eed.zip |
Imported from util-linux-2.7.1 tarball.
Diffstat (limited to 'disk-utils')
-rw-r--r-- | disk-utils/Makefile | 30 | ||||
-rw-r--r-- | disk-utils/README.fdisk.alpha | 16 | ||||
-rw-r--r-- | disk-utils/README.fdisk.bsd | 28 | ||||
-rw-r--r-- | disk-utils/bitops.h | 54 | ||||
-rw-r--r-- | disk-utils/cfdisk.c | 501 | ||||
-rw-r--r-- | disk-utils/fdformat.c | 14 | ||||
-rw-r--r-- | disk-utils/fdisk.8 | 2 | ||||
-rw-r--r-- | disk-utils/fdisk.c | 59 | ||||
-rw-r--r-- | disk-utils/fdisk.h | 1 | ||||
-rw-r--r-- | disk-utils/fdisklabel.c | 281 | ||||
-rw-r--r-- | disk-utils/fdisklabel.h | 124 | ||||
-rw-r--r-- | disk-utils/fsck.minix.8 | 16 | ||||
-rw-r--r-- | disk-utils/fsck.minix.c | 572 | ||||
-rw-r--r-- | disk-utils/llseek.c | 83 | ||||
-rw-r--r-- | disk-utils/mkfs.c | 8 | ||||
-rw-r--r-- | disk-utils/mkfs.minix.8 | 42 | ||||
-rw-r--r-- | disk-utils/mkfs.minix.c | 438 | ||||
-rw-r--r-- | disk-utils/mkswap.8 | 2 | ||||
-rw-r--r-- | disk-utils/mkswap.c | 28 | ||||
-rw-r--r-- | disk-utils/setfdprm.c | 19 | ||||
-rw-r--r-- | disk-utils/sfdisk.8 | 497 | ||||
-rw-r--r-- | disk-utils/sfdisk.c | 2712 | ||||
-rw-r--r-- | disk-utils/sfdisk.examples | 264 |
23 files changed, 5057 insertions, 734 deletions
diff --git a/disk-utils/Makefile b/disk-utils/Makefile index 739d12834..fac3134ba 100644 --- a/disk-utils/Makefile +++ b/disk-utils/Makefile @@ -8,17 +8,20 @@ include ../MCONFIG # Where to put man pages? -MAN8= cfdisk.8 fdformat.8 fsck.minix.8 \ - mkfs.8 mkfs.minix.8 mkswap.8 setfdprm.8 +MAN8= fdformat.8 mkswap.8 setfdprm.8 -MAN8.FDISK= fdisk.8 +ifneq "$(CPU)" "sparc" +MAN8:=$(MAN8) fdisk.8 cfdisk.8 sfdisk.8 fsck.minix.8 mkfs.8 mkfs.minix.8 +endif # Where to put binaries? # See the "install" rule for the links. . . -SBIN= cfdisk fsck.minix mkfs mkfs.minix mkswap +SBIN= mkfs mkswap -SBIN.FDISK= fdisk +ifneq "$(CPU)" "sparc" +SBIN:=$(SBIN) fdisk cfdisk sfdisk fsck.minix mkfs.minix +endif USRBIN= fdformat setfdprm @@ -26,27 +29,30 @@ USRBIN= fdformat setfdprm ETC= fdprm -ifeq "$(HAVE_FDISK)" "no" -SBIN:=$(SBIN) $(SBIN.FDISK) -MAN8:=$(MAN8) $(MAN8.FDISK) -endif - all: $(SBIN) $(USRBIN) cfdisk: cfdisk.o llseek.o - $(CC) $(LDFLAGS) $^ -o $@ -lcurses -ltermcap -lm + $(CC) $(LDFLAGS) $^ -o $@ $(LIBCURSES) -lm + +# not installed by default +activate: sfdisk + rm -f activate + ln -s sfdisk activate # Rules for everything else fdformat: fdformat.o fdisk: fdisk.o fdisklabel.o llseek.o +sfdisk: sfdisk.o fsck.minix: fsck.minix.o +fsck.minix.o: fsck.minix.c bitops.h mkfs: mkfs.o mkfs.minix: mkfs.minix.o +mkfs.minix.o: mkfs.minix.c bitops.h mkswap: mkswap.o setfdprm: setfdprm.o fdisk.o: fdisk.c fdisk.h -fdisklabel.o: fdisklabel.c fdisk.h +fdisklabel.o: fdisklabel.c fdisk.h fdisklabel.h install: all $(INSTALLDIR) $(SBINDIR) $(USRBINDIR) $(ETCDIR) diff --git a/disk-utils/README.fdisk.alpha b/disk-utils/README.fdisk.alpha deleted file mode 100644 index da6e87342..000000000 --- a/disk-utils/README.fdisk.alpha +++ /dev/null @@ -1,16 +0,0 @@ - -There are some things which have to be done for the alpha version: -- LABELSECTOR, LABELOFFSET, BBSIZE & SBSIZE are undefined in fdisklabel.h - These values are different for different versions of NetBSD and I don't - have the alpha source tree for NetBSD yet (It's not in 1.0 but in current). - I guess Linux/Alpha uses the same values. -- The alpha fdisklabel.c requires a few functions from fdisk.c. - ("make test" shows the undefined symbols when fdisk.c is missing) - All the other functions/variables shouldn't be declared. I didn't do - that because I didn't want to change much in fdisk.c. -- The disklabel in fdisklabel.c is the NetBSD disklabel which might - differ from the Linux/Alpha disklabel in some parts. -- bselect () should be called from main () immediately. Under Linux/Alpha - it's the main menu and not a submenu. - -fasten@informatik.uni-bonn.de diff --git a/disk-utils/README.fdisk.bsd b/disk-utils/README.fdisk.bsd deleted file mode 100644 index 705df90f8..000000000 --- a/disk-utils/README.fdisk.bsd +++ /dev/null @@ -1,28 +0,0 @@ - -All changes in fdisk.c are marked with this comment: /* bf */ - -I added some explanatory comments to make it easier to see what -changed and why. You'll probably want to remove them. - -There's a function sync_disks() in fdisklabel.c which could be called -from write_table() in fdisk.c (line 1216) (and be moved to fdisk.c) -to save a few bytes. - -There's a function edit_int() in fdisklabel.c which I added because read_int() -had no default value. In fdisk v2.0d it has so edit_int could be replaces by -read_int(). The function which uses edit_int() (bsd_edit_disklabel ()) is a -bit crufty anyhow: -- The disklabel contains some values which are probably meaningless for IDE or - SCSI drives, I made them editable but I don't know any sensible range of - values (bad for read_int()). (interleave, trackskew, cylskew) -- I made the values secsize/nsectors/ntracks/ncylinders editable for Linux/Alpha - but not for Linux/i386 because under Linux/i386 the disklabel is inside a - DOS partition so the disklabel was written by an OS which got along with the - disk and should have left the correct values there. - -I've put the BSD copyright (which applies to fdisklabel.h and -alpha_bootblock_checksum, bsd_dkcksum, bsd_print_disklabel in fdisklabel.c) -into a separate man page. This way all Linux versions of BSD programs can refer -to ths bsd.<n> man page. - -fasten@informatik.uni-bonn.de diff --git a/disk-utils/bitops.h b/disk-utils/bitops.h new file mode 100644 index 000000000..270dc2d8f --- /dev/null +++ b/disk-utils/bitops.h @@ -0,0 +1,54 @@ +#ifdef __i386__ + +#define bitop(name,op) \ +static inline int name(char * addr,unsigned int nr) \ +{ \ +int __res; \ +__asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \ +:"=g" (__res) \ +:"r" (nr),"m" (*(addr)),"0" (0)); \ +return __res; \ +} + +bitop(bit,"") +bitop(setbit,"s") +bitop(clrbit,"r") + +#elif defined(__mc68000__) + +#define bitop(name,op) \ +static inline int name (char *addr, unsigned int nr) \ +{ \ + char __res; \ + __asm__ __volatile__("bf" op " %2@{%1:#1}; sne %0" \ + : "=d" (__res) \ + : "d" (nr ^ 15), "a" (addr)); \ + return __res != 0; \ +} + +bitop (bit, "tst") +bitop (setbit, "set") +bitop (clrbit, "clr") + +#else +static inline int bit(char * addr,unsigned int nr) +{ + return (addr[nr >> 3] & (1<<(nr & 7))) != 0; +} + +static inline int setbit(char * addr,unsigned int nr) +{ + int __res = bit(addr, nr); + addr[nr >> 3] |= (1<<(nr & 7)); + return __res != 0; \ +} + +static inline int clrbit(char * addr,unsigned int nr) +{ + int __res = bit(addr, nr); + addr[nr >> 3] &= ~(1<<(nr & 7)); + return __res != 0; +} + +#endif + diff --git a/disk-utils/cfdisk.c b/disk-utils/cfdisk.c index beb46e508..1b87aae79 100644 --- a/disk-utils/cfdisk.c +++ b/disk-utils/cfdisk.c @@ -29,6 +29,7 @@ * >2GB patches: Sat Feb 11 09:08:10 1995, faith@cs.unc.edu * Prettier menus: Sat Feb 11 09:08:25 1995, Janne Kukonlehto * <jtklehto@stekt.oulu.fi> + * Versions 0.8e-h: aeb@cwi.nl * ****************************************************************************/ @@ -44,6 +45,7 @@ #include <signal.h> #include <math.h> #include <string.h> +#include <sys/stat.h> #include <sys/ioctl.h> #include <linux/genhd.h> #include <linux/hdreg.h> @@ -55,12 +57,10 @@ typedef long long ext2_loff_t; typedef long ext2_loff_t; #endif -extern ext2_loff_t ext2_llseek(unsigned int fd, - ext2_loff_t offset, +extern ext2_loff_t ext2_llseek(unsigned int fd, ext2_loff_t offset, unsigned int origin); - -#define VERSION "0.8d BETA (>2GB)" +#define VERSION "0.8i" #define DEFAULT_DEVICE "/dev/hda" #define ALTERNATE_DEVICE "/dev/sda" @@ -79,7 +79,8 @@ extern ext2_loff_t ext2_llseek(unsigned int fd, #define UNUSABLE -1 #define FREE_SPACE 0x00 -#define EXTENDED 0x05 +#define DOS_EXTENDED 0x05 +#define LINUX_EXTENDED 0x85 #define LINUX_MINIX 0x81 #define LINUX_SWAP 0x82 #define LINUX 0x83 @@ -107,6 +108,7 @@ extern ext2_loff_t ext2_llseek(unsigned int fd, #define BAD_CYLINDERS "Illegal cylinders value" #define BAD_HEADS "Illegal heads value" #define BAD_SECTORS "Illegal sectors value" +#define READONLY_WARN "Opened disk read-only - you have no permission to write" #define WRITE_WARN "Warning!! This may destroy data on your disk!" #define YES_NO "Please enter `yes' or `no'" #define WRITING_PART "Writing partition table to disk..." @@ -155,6 +157,11 @@ extern ext2_loff_t ext2_llseek(unsigned int fd, s |= (sector >> 2) & 0xC0;\ } +#define is_extended(x) ((x) == DOS_EXTENDED || (x) == LINUX_EXTENDED) + +/* we might also want to recognise 0xe and 0xf */ +#define is_dos_partition(x) ((x) == 1 || (x) == 4 || (x) == 6) + #define ALIGNMENT 2 typedef union { struct { @@ -176,6 +183,8 @@ typedef struct { int flags; /* active == 0x80 */ int id; /* filesystem type */ int num; /* number of partition -- primary vs. logical */ +#define LABELSZ 11 + char dos_label[LABELSZ+1]; } partition_info; char *disk_device = DEFAULT_DEVICE; @@ -185,6 +194,8 @@ int sectors = 0; int cylinders = 0; int changed = FALSE; int opened = FALSE; +int opentype; +int curses_started = 0; partition_info p_info[MAXIMUM_PARTS]; partition_info ext_info; @@ -227,12 +238,20 @@ char *partition_type[NUM_PART_TYPES] = { [LINUX_SWAP] = "Linux Swap", [LINUX] = "Linux", [FREE_SPACE] = "Free Space", - [EXTENDED] = "Extended", - [0x01] = "DOS 12-bit FAT", - [0x04] = "DOS 16-bit < 32Mb", - [0x06] = "DOS 16-bit >=32Mb", - [0x07] = "OS/2 HPFS", + [DOS_EXTENDED]= "Extended", + [LINUX_EXTENDED] = "Linux extended", + [0x01] = "DOS FAT12", + [0x04] = "DOS FAT16", + [0x06] = "DOS FAT16 (big)", + [0x07] = "OS/2 HPFS or NTFS", [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)", [0xA5] = "BSD/386", /* The rest of these are taken from A. V. Le Blanc's (LeBlanc@mcc.ac.uk) @@ -279,7 +298,6 @@ void fdexit(int ret) "page for additional information.\n" ); } - exit(ret); } @@ -346,7 +364,7 @@ void clear_warning(void) { int i; - if (!warning_last_time) + if (!curses_started || !warning_last_time) return; move(WARNING_START,0); @@ -358,37 +376,56 @@ void clear_warning(void) void print_warning(char *s) { - mvaddstr(WARNING_START, (COLS-strlen(s))/2, s); - putchar(BELL); /* CTRL-G */ + if (!curses_started) { + fprintf(stderr, "%s\n", s); + } else { + mvaddstr(WARNING_START, (COLS-strlen(s))/2, s); + putchar(BELL); /* CTRL-G */ - warning_last_time = TRUE; + warning_last_time = TRUE; + } } +void die_x(int ret); + void fatal(char *s) { char str[LINE_LENGTH]; - sprintf(str, "FATAL ERROR: %s", s); - mvaddstr(WARNING_START, (COLS-strlen(str))/2, str); - sprintf(str, "Press any key to exit fdisk"); - mvaddstr(WARNING_START+1, (COLS-strlen(str))/2, str); - putchar(BELL); /* CTRL-G */ - - refresh(); + if (curses_started) { + sprintf(str, "FATAL ERROR: %s", s); + mvaddstr(WARNING_START, (COLS-strlen(str))/2, str); + sprintf(str, "Press any key to exit fdisk"); + mvaddstr(WARNING_START+1, (COLS-strlen(str))/2, str); + putchar(BELL); /* CTRL-G */ + refresh(); + (void)getch(); + die_x(1); + } else { + fprintf(stderr, "FATAL ERROR: %s\n", s); + exit(1); + } +} - (void)getch(); +void die(int dummy) +{ + die_x(0); +} +void die_x(int ret) +{ signal(SIGINT, old_SIGINT); signal(SIGTERM, old_SIGTERM); mvcur(0, COLS-1, LINES-1, 0); nl(); endwin(); - fdexit(1); + printf("\n"); + fdexit(ret); } void read_sector(char *buffer, int sect_num) { - if (ext2_llseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0) + if (ext2_llseek(fd, ((ext2_loff_t) sect_num)*SECTOR_SIZE, SEEK_SET) < 0) fatal(BAD_SEEK); if (read(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) fatal(BAD_READ); @@ -396,12 +433,30 @@ void read_sector(char *buffer, int sect_num) void write_sector(char *buffer, int sect_num) { - if (ext2_llseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0) + if (ext2_llseek(fd, ((ext2_loff_t) sect_num)*SECTOR_SIZE, SEEK_SET) < 0) fatal(BAD_SEEK); if (write(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) fatal(BAD_WRITE); } +void get_dos_label(int i) +{ + char label[LABELSZ+1]; + ext2_loff_t offset; + int j; + + offset = ((ext2_loff_t) p_info[i].first_sector + p_info[i].offset) + * SECTOR_SIZE + 43; + if (ext2_llseek(fd, offset, SEEK_SET) == offset + && read(fd, &label, LABELSZ) == LABELSZ) { + for(j=0; j<LABELSZ; j++) + if(!isascii(label[j])) + label[j] = 0; + label[LABELSZ] = 0; + strcpy(p_info[i].dos_label, label); + } +} + void check_part_info(void) { int i, pri = 0, log = 0; @@ -411,7 +466,7 @@ void check_part_info(void) pri++; else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num)) log++; - if (ext_info.id == EXTENDED) + if (is_extended(ext_info.id)) if (log > 0) pri++; else { @@ -423,10 +478,10 @@ void check_part_info(void) ext_info.num = PRIMARY; } - if (pri >= 4) + if (pri >= 4) { for (i = 0; i < num_parts; i++) if (p_info[i].id == FREE_SPACE || p_info[i].id == UNUSABLE) - if (ext_info.id == EXTENDED) + if (is_extended(ext_info.id)) if (p_info[i].first_sector >= ext_info.first_sector && p_info[i].last_sector <= ext_info.last_sector) { p_info[i].id = FREE_SPACE; @@ -447,16 +502,16 @@ void check_part_info(void) p_info[i].num = LOGICAL; } else p_info[i].id = UNUSABLE; - else /* if (ext_info.id != EXTENDED) */ + else /* if (!is_extended(ext_info.id)) */ p_info[i].id = UNUSABLE; else /* if (p_info[i].id > 0) */ while (0); /* Leave these alone */ - else /* if (pri < 4) */ + } else { /* if (pri < 4) */ for (i = 0; i < num_parts; i++) { if (p_info[i].id == UNUSABLE) p_info[i].id = FREE_SPACE; if (p_info[i].id == FREE_SPACE) - if (ext_info.id == EXTENDED) + if (is_extended(ext_info.id)) if (p_info[i].first_sector >= ext_info.first_sector && p_info[i].last_sector <= ext_info.last_sector) p_info[i].num = LOGICAL; @@ -474,11 +529,12 @@ void check_part_info(void) p_info[i].num = PRI_OR_LOG; else p_info[i].num = PRIMARY; - else /* if (ext_info.id != EXTENDED) */ + else /* if (!is_extended(ext_info.id)) */ p_info[i].num = PRI_OR_LOG; else /* if (p_info[i].id > 0) */ while (0); /* Leave these alone */ } + } } void remove_part(int i) @@ -491,8 +547,7 @@ void remove_part(int i) num_parts--; } -void insert_part(int i, int num, int id, int flags, int first, int last, - int offset) +void insert_empty_part(int i, int first, int last) { int p; @@ -501,10 +556,11 @@ void insert_part(int i, int num, int id, int flags, int first, int last, p_info[i].first_sector = first; p_info[i].last_sector = last; - p_info[i].offset = offset; - p_info[i].flags = flags; - p_info[i].id = id; - p_info[i].num = num; + p_info[i].offset = 0; + p_info[i].flags = 0; + p_info[i].id = FREE_SPACE; + p_info[i].num = PRI_OR_LOG; + p_info[i].dos_label[0] = 0; num_parts++; } @@ -548,8 +604,10 @@ void del_part(int i) * last logical drive; and if there are any other logical drives * then renumber the ones after "num". */ - if (i == 0 || (i > 0 && IS_PRIMARY(p_info[i-1].num))) + if (i == 0 || (i > 0 && IS_PRIMARY(p_info[i-1].num))) { ext_info.first_sector = p_info[i].last_sector + 1; + ext_info.offset = 0; + } if (i == num_parts-1 || (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num))) ext_info.last_sector = p_info[i].first_sector - 1; @@ -562,7 +620,8 @@ void del_part(int i) check_part_info(); } -int add_part(int num, int id, int flags, int first, int last, int offset) +int add_part(int num, int id, int flags, int first, int last, int offset, + int want_label) { int i, pri = 0, log = 0; @@ -570,45 +629,51 @@ int add_part(int num, int id, int flags, int first, int last, int offset) first < 0 || first >= cylinders*heads*sectors || last < 0 || - last >= cylinders*heads*sectors) - return -1; + last >= cylinders*heads*sectors) { + return -1; /* bad start or end */ + } for (i = 0; i < num_parts; i++) if (p_info[i].id > 0 && IS_PRIMARY(p_info[i].num)) pri++; else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num)) log++; - if (ext_info.id == EXTENDED && log > 0) + if (is_extended(ext_info.id) && log > 0) pri++; if (IS_PRIMARY(num)) - if (pri >= 4) - return -1; - else + if (pri >= 4) { + return -1; /* no room for more */ + } else pri++; - for (i = 0; p_info[i].last_sector < first; i++); + for (i = 0; i < num_parts && p_info[i].last_sector < first; i++); - if (p_info[i].id != FREE_SPACE || last > p_info[i].last_sector) + if (i == num_parts || p_info[i].id != FREE_SPACE + || last > p_info[i].last_sector) { return -1; + } - if (id == EXTENDED) - if (ext_info.id != FREE_SPACE) - return -1; + if (is_extended(id)) { + if (ext_info.id != FREE_SPACE) { + return -1; /* second extended */ + } else if (IS_PRIMARY(num)) { ext_info.first_sector = first; ext_info.last_sector = last; ext_info.offset = offset; ext_info.flags = flags; - ext_info.id = EXTENDED; + ext_info.id = id; ext_info.num = num; - + ext_info.dos_label[0] = 0; return 0; - } else - return -1; + } else { + return -1; /* explicit extended logical */ + } + } if (IS_LOGICAL(num)) { - if (ext_info.id != EXTENDED) { + if (!is_extended(ext_info.id)) { print_warning("!!!! Internal error creating logical " "drive with no extended partition !!!!"); } else { @@ -626,29 +691,29 @@ int add_part(int num, int id, int flags, int first, int last, int offset) if (first == 0) { ext_info.first_sector = 0; ext_info.offset = first = offset; - } else + } else { ext_info.first_sector = first; + } } } else if (last > ext_info.last_sector) { if (i > 0 && IS_PRIMARY(p_info[i-1].num)) { print_warning(TWO_EXTENDEDS); return -1; - } else + } else { ext_info.last_sector = last; + } } } } if (first != p_info[i].first_sector && !(IS_LOGICAL(num) && first == offset)) { - insert_part(i, PRI_OR_LOG, FREE_SPACE, 0, - p_info[i].first_sector, first-1, 0); + insert_empty_part(i, p_info[i].first_sector, first-1); i++; } if (last != p_info[i].last_sector) - insert_part(i+1, PRI_OR_LOG, FREE_SPACE, 0, - last+1, p_info[i].last_sector, 0); + insert_empty_part(i+1, last+1, p_info[i].last_sector); p_info[i].first_sector = first; p_info[i].last_sector = last; @@ -656,6 +721,9 @@ int add_part(int num, int id, int flags, int first, int last, int offset) p_info[i].flags = flags; p_info[i].id = id; p_info[i].num = num; + p_info[i].dos_label[0] = 0; + if (want_label && is_dos_partition(id)) + get_dos_label(i); check_part_info(); @@ -668,7 +736,7 @@ int find_primary(void) while (cur < num_parts && IS_PRIMARY(num)) if ((p_info[cur].id > 0 && p_info[cur].num == num) || - (ext_info.id == EXTENDED && ext_info.num == num)) { + (is_extended(ext_info.id) && ext_info.num == num)) { num++; cur = 0; } else @@ -1046,7 +1114,7 @@ void new_part(int i) return; } - if (IS_LOGICAL(num) && ext_info.id != EXTENDED) { + if (IS_LOGICAL(num) && !is_extended(ext_info.id)) { /* We want to add a logical partition, but need to create an * extended partition first. */ @@ -1054,8 +1122,9 @@ void new_part(int i) print_warning(NEED_EXT); return; } - (void)add_part(ext, EXTENDED, 0, first, last, - (first == 0 ? sectors : 0)); + (void) add_part(ext, DOS_EXTENDED, 0, first, last, + (first == 0 ? sectors : 0), 0); + first = ext_info.first_sector + ext_info.offset; } if (IS_LOGICAL(num)) @@ -1065,7 +1134,7 @@ void new_part(int i) if (first == 0 || IS_LOGICAL(num)) offset = sectors; - (void)add_part(num, id, flags, first, last, offset); + (void) add_part(num, id, flags, first, last, offset, 0); } void clear_p_info(void) @@ -1093,8 +1162,20 @@ void fill_p_info(void) partition_table buffer; partition_info tmp_ext = { 0, 0, 0, 0, FREE_SPACE, PRIMARY }; - if ((fd = open(disk_device, O_RDWR)) < 0) - fatal(BAD_OPEN); + if ((fd = open(disk_device, O_RDWR)) < 0) { + if ((fd = open(disk_device, O_RDONLY)) < 0) + fatal(BAD_OPEN); + opentype = O_RDONLY; + print_warning(READONLY_WARN); + if (curses_started) { + refresh(); + getch(); + clear_warning(); + } + } else + opentype = O_RDWR; + opened = TRUE; + read_sector(buffer.c.b, 0); if (!ioctl(fd, HDIO_GETGEO, &geometry)) { @@ -1113,52 +1194,53 @@ void fill_p_info(void) if (!zero_table) { for (i = 0; i < 4; i++) { + int bs = buffer.p.part[i].start_sect; + if (buffer.p.part[i].sys_ind > 0 && add_part(i, buffer.p.part[i].sys_ind, buffer.p.part[i].boot_ind, - ((buffer.p.part[i].start_sect <= sectors) ? - 0 : buffer.p.part[i].start_sect), + ((bs <= sectors) ? 0 : bs), buffer.p.part[i].start_sect + buffer.p.part[i].nr_sects - 1, - ((buffer.p.part[i].start_sect <= sectors) ? - buffer.p.part[i].start_sect : 0))) { + ((bs <= sectors) ? bs : 0), + 1)) { fatal(BAD_PRIMARY); } - if (buffer.p.part[i].sys_ind == EXTENDED) + if (is_extended(buffer.p.part[i].sys_ind)) tmp_ext = ext_info; } - if (tmp_ext.id == EXTENDED) { + if (is_extended(tmp_ext.id)) { ext_info = tmp_ext; - logical_sectors[logical] = ext_info.first_sector; + logical_sectors[logical] = + ext_info.first_sector + ext_info.offset; read_sector(buffer.c.b, logical_sectors[logical++]); i = 4; do { for (p = 0; p < 4 && (!buffer.p.part[p].sys_ind || - buffer.p.part[p].sys_ind == 5); + is_extended(buffer.p.part[p].sys_ind)); p++); - if (p > 3) - fatal(BAD_LOGICAL); - if (add_part(i++, + if (p < 4 && add_part(i++, buffer.p.part[p].sys_ind, buffer.p.part[p].boot_ind, logical_sectors[logical-1], logical_sectors[logical-1] + buffer.p.part[p].start_sect + buffer.p.part[p].nr_sects - 1, - buffer.p.part[p].start_sect)) { + buffer.p.part[p].start_sect, + 1)) { fatal(BAD_LOGICAL); } for (p = 0; - p < 4 && buffer.p.part[p].sys_ind != 5; + p < 4 && !is_extended(buffer.p.part[p].sys_ind); p++); if (p < 4) { - logical_sectors[logical] = - ext_info.first_sector + buffer.p.part[p].start_sect; + logical_sectors[logical] = ext_info.first_sector + + ext_info.offset + buffer.p.part[p].start_sect; read_sector(buffer.c.b, logical_sectors[logical++]); } } while (p < 4 && logical < MAXIMUM_PARTS-4); @@ -1197,7 +1279,7 @@ void fill_primary_table(partition_table *buffer) if (IS_PRIMARY(p_info[i].num)) fill_part_table(&(buffer->p.part[p_info[i].num]), &(p_info[i])); - if (ext_info.id == EXTENDED) + if (is_extended(ext_info.id)) fill_part_table(&(buffer->p.part[ext_info.num]), &ext_info); buffer->p.flag = PART_TABLE_FLAG; @@ -1228,8 +1310,8 @@ void fill_logical_table(partition_table *buffer, partition_info *pi) pi = &(p_info[i]); p->boot_ind = 0; - p->sys_ind = 5; - p->start_sect = pi->first_sector - ext_info.first_sector; + p->sys_ind = DOS_EXTENDED; + p->start_sect = pi->first_sector - ext_info.first_sector - ext_info.offset; p->nr_sects = pi->last_sector - pi->first_sector + 1; sects = ((pi->first_sector/(sectors*heads) > 1023) ? heads*sectors*1024 - 1 : pi->first_sector); @@ -1246,62 +1328,78 @@ void write_part_table(void) { int i, done = FALSE, len; partition_table buffer; + struct stat s; + int is_bdev; char response[LINE_LENGTH]; - print_warning(WRITE_WARN); - - while (!done) { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Are you sure you want write the partition table to disk? (yes or no): "); - - len = get_string(response, LINE_LENGTH, NULL); - - clear_warning(); + if (opentype == O_RDONLY) { + print_warning(READONLY_WARN); + refresh(); + getch(); + clear_warning(); + return; + } - if (len == GS_ESCAPE) - return; - else if (len == 2 && - toupper(response[0]) == 'N' && - toupper(response[1]) == 'O') { - print_warning(NO_WRITE); - return; - } else if (len == 3 && - toupper(response[0]) == 'Y' && - toupper(response[1]) == 'E' && - toupper(response[2]) == 'S') - done = TRUE; - else - print_warning(YES_NO); + is_bdev = 0; + if(fstat(fd, &s) == 0 && S_ISBLK(s.st_mode)) + is_bdev = 1; + + if (is_bdev) { + print_warning(WRITE_WARN); + + while (!done) { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Are you sure you want write the partition table " + "to disk? (yes or no): "); + len = get_string(response, LINE_LENGTH, NULL); + clear_warning(); + if (len == GS_ESCAPE) + return; + else if (len == 2 && + toupper(response[0]) == 'N' && + toupper(response[1]) == 'O') { + print_warning(NO_WRITE); + return; + } else if (len == 3 && + toupper(response[0]) == 'Y' && + toupper(response[1]) == 'E' && + toupper(response[2]) == 'S') + done = TRUE; + else + print_warning(YES_NO); + } + + clear_warning(); + print_warning(WRITING_PART); + refresh(); } - clear_warning(); - print_warning(WRITING_PART); - refresh(); - read_sector(buffer.c.b, 0); fill_primary_table(&buffer); write_sector(buffer.c.b, 0); for (i = 0; i < num_parts; i++) if (IS_LOGICAL(p_info[i].num)) { - /* Read the extended partition table from disk ??? KEM */ read_sector(buffer.c.b, p_info[i].first_sector); fill_logical_table(&buffer, &(p_info[i])); write_sector(buffer.c.b, p_info[i].first_sector); } - sync(); - sleep(2); - if (!ioctl(fd,BLKRRPART)) - changed = TRUE; - sync(); - sleep(4); - - clear_warning(); - if (changed) - print_warning(YES_WRITE); - else - print_warning(RRPART_FAILED); + if (is_bdev) { + sync(); + sleep(2); + if (!ioctl(fd,BLKRRPART)) + changed = TRUE; + sync(); + sleep(4); + + clear_warning(); + if (changed) + print_warning(YES_WRITE); + else + print_warning(RRPART_FAILED); + } else + print_warning(YES_WRITE); } void fp_printf(FILE *fp, char *format, ...) @@ -1380,12 +1478,14 @@ void print_raw_table(void) fp_printf(fp, "Disk Drive: %s\n", disk_device); + fp_printf(fp, "Sector 0:\n"); read_sector(buffer.c.b, 0); fill_primary_table(&buffer); print_file_buffer(fp, buffer.c.b); for (i = 0; i < num_parts; i++) if (IS_LOGICAL(p_info[i].num)) { + fp_printf(fp, "Sector %d:\n", p_info[i].first_sector); read_sector(buffer.c.b, p_info[i].first_sector); fill_logical_table(&buffer, &(p_info[i])); print_file_buffer(fp, buffer.c.b); @@ -1402,7 +1502,7 @@ void print_raw_table(void) void print_p_info_entry(FILE *fp, partition_info *p) { int size; - char part_str[21]; + char part_str[40]; if (p->id == UNUSABLE) fp_printf(fp, " None "); @@ -1418,45 +1518,39 @@ void print_p_info_entry(FILE *fp, partition_info *p) fp_printf(fp, " "); - fp_printf(fp, "%7d%c", p->first_sector, + fp_printf(fp, "%8d%c", p->first_sector, ((p->first_sector/(sectors*heads)) != ((float)p->first_sector/(sectors*heads)) ? '*' : ' ')); - fp_printf(fp, " "); - - fp_printf(fp, "%7d%c", p->last_sector, + fp_printf(fp, "%8d%c", p->last_sector, (((p->last_sector+1)/(sectors*heads)) != ((float)(p->last_sector+1)/(sectors*heads)) ? '*' : ' ')); - fp_printf(fp, " "); - - fp_printf(fp, "%6d%c", p->offset, + fp_printf(fp, "%7d%c", p->offset, ((((p->first_sector == 0 || IS_LOGICAL(p->num)) && (p->offset != sectors)) || (p->first_sector != 0 && IS_PRIMARY(p->num) && p->offset != 0)) ? '#' : ' ')); - fp_printf(fp, " "); - size = p->last_sector - p->first_sector + 1; - fp_printf(fp, "%7d%c", size, + fp_printf(fp, "%8d%c", size, ((size/(sectors*heads)) != ((float)size/(sectors*heads)) ? '*' : ' ')); fp_printf(fp, " "); if (p->id == UNUSABLE) - sprintf(part_str, "%.16s", "Unusable"); + sprintf(part_str, "%.17s", "Unusable"); else if (p->id == FREE_SPACE) - sprintf(part_str, "%.16s", "Free Space"); + sprintf(part_str, "%.17s", "Free Space"); else if (partition_type[p->id]) - sprintf(part_str, "%.16s (%02X)", partition_type[p->id], p->id); + sprintf(part_str, "%.17s (%02X)", partition_type[p->id], p->id); else - sprintf(part_str, "%.16s (%02X)", "Unknown", p->id); - fp_printf(fp, "%-21.21s", part_str); + sprintf(part_str, "%.17s (%02X)", "Unknown", p->id); + fp_printf(fp, "%-22.22s", part_str); fp_printf(fp, " "); @@ -1474,7 +1568,7 @@ void print_p_info(void) { char fname[LINE_LENGTH]; FILE *fp; - int i, to_file, pext = (ext_info.id == EXTENDED); + int i, to_file, pext = is_extended(ext_info.id); if (print_only) { fp = stdout; @@ -1502,9 +1596,9 @@ void print_p_info(void) fp_printf(fp, "Partition Table for %s\n", disk_device); fp_printf(fp, "\n"); - fp_printf(fp, " First Last\n"); - fp_printf(fp, " # Type Sector Sector Offset Length Filesystem Type (ID) Flags\n"); - fp_printf(fp, "-- ------- -------- -------- ------- -------- --------------------- ---------\n"); + fp_printf(fp, " First Last\n"); + fp_printf(fp, " # Type Sector Sector Offset Length Filesystem Type (ID) Flags\n"); + fp_printf(fp, "-- ------- -------- --------- ------ --------- ---------------------- ---------\n"); for (i = 0; i < num_parts; i++) { if (pext && (p_info[i].first_sector >= ext_info.first_sector)) { @@ -1557,7 +1651,7 @@ void print_part_entry(FILE *fp, int num, partition_info *pi) ec = end / heads; } - fp_printf(fp, "%2d 0x%02X %4d %4d %4d 0x%02X %4d %4d %4d %7d %7d\n", + fp_printf(fp, "%2d 0x%02X %4d %4d %4d 0x%02X %4d %4d %4d %7d %9d\n", num+1, flags, sh, ss, sc, id, eh, es, ec, first, size); } @@ -1594,9 +1688,9 @@ void print_part_table(void) fp_printf(fp, "Partition Table for %s\n", disk_device); fp_printf(fp, "\n"); - fp_printf(fp, " ---Starting--- ----Ending---- Start Number\n"); - fp_printf(fp, " # Flags Head Sect Cyl ID Head Sect Cyl Sector Sectors\n"); - fp_printf(fp, "-- ----- ---- ---- ---- ---- ---- ---- ---- ------- -------\n"); + fp_printf(fp, " ---Starting--- ----Ending---- Start Number of\n"); + fp_printf(fp, " # Flags Head Sect Cyl ID Head Sect Cyl Sector Sectors\n"); + fp_printf(fp, "-- ----- ---- ---- ---- ---- ---- ---- ---- ------- ---------\n"); for (i = 0; i < 4; i++) { for (j = 0; @@ -1604,7 +1698,7 @@ void print_part_table(void) j++); if (j < num_parts) { print_part_entry(fp, i, &(p_info[j])); - } else if (ext_info.id == EXTENDED && ext_info.num == i) { + } else if (is_extended(ext_info.id) && ext_info.num == i) { print_part_entry(fp, i, &ext_info); } else { print_part_entry(fp, i, NULL); @@ -1667,7 +1761,7 @@ void display_help() "allows you to create, delete and modify partitions on your hard", "disk drive.", "", - "Copyright (C) 1994 Kevin E. Martin", + "Copyright (C) 1994-1997 Kevin E. Martin & aeb", "", "Command Meaning", "------- -------", @@ -1796,8 +1890,10 @@ int change_geometry(void) } if (ret_val) { - if (p_info[num_parts-1].last_sector > heads*sectors*cylinders-1) { - while (p_info[num_parts-1].first_sector > heads*sectors*cylinders-1) { + int disk_end = heads*sectors*cylinders-1; + + if (p_info[num_parts-1].last_sector > disk_end) { + while (p_info[num_parts-1].first_sector > disk_end) { if (p_info[num_parts-1].id == FREE_SPACE || p_info[num_parts-1].id == UNUSABLE) remove_part(num_parts-1); @@ -1805,18 +1901,18 @@ int change_geometry(void) del_part(num_parts-1); } - p_info[num_parts-1].last_sector = heads*sectors*cylinders - 1; + p_info[num_parts-1].last_sector = disk_end; - if (ext_info.last_sector > heads*sectors*cylinders-1) - ext_info.last_sector = heads*sectors*cylinders - 1; - } else if (p_info[num_parts-1].last_sector < heads*sectors*cylinders-1) { + if (ext_info.last_sector > disk_end) + ext_info.last_sector = disk_end; + } else if (p_info[num_parts-1].last_sector < disk_end) { if (p_info[num_parts-1].id == FREE_SPACE || p_info[num_parts-1].id == UNUSABLE) { - p_info[num_parts-1].last_sector = heads*sectors*cylinders - 1; + p_info[num_parts-1].last_sector = disk_end; } else { - insert_part(num_parts, PRI_OR_LOG, FREE_SPACE, 0, - p_info[num_parts-1].last_sector+1, - heads*sectors*cylinders-1, 0); + insert_empty_part(num_parts, + p_info[num_parts-1].last_sector+1, + disk_end); } } @@ -1878,7 +1974,7 @@ void change_id(int i) if (new_id == 0) print_warning(ID_EMPTY); - else if (new_id == EXTENDED) + else if (is_extended(new_id)) print_warning(ID_EXT); else p_info[i].id = new_id; @@ -1935,6 +2031,11 @@ void draw_partition(int i) else mvprintw(y, FSTYPE_START, "Unknown (%02X)", p_info[i].id); + if (p_info[i].dos_label[0]) { + int l = strlen(p_info[i].dos_label); + mvprintw(y, SIZE_START-5-l, " [%s] ", p_info[i].dos_label); + } + size = p_info[i].last_sector - p_info[i].first_sector + 1; if (display_units == SECTORS) mvprintw(y, SIZE_START, "%9d", size); @@ -2055,16 +2156,6 @@ int draw_cursor(int move) return 0; } -void die(int dummy) -{ - signal(SIGINT, old_SIGINT); - signal(SIGTERM, old_SIGTERM); - mvcur(0, COLS-1, LINES-1, 0); - nl(); - endwin(); - fdexit(0); -} - void do_curses_fdisk(void) { int done = FALSE; @@ -2085,7 +2176,7 @@ void do_curses_fdisk(void) { 'W', "Write", "Write partition table to disk (this might destroy data)" }, { 0, NULL, NULL } }; - + curses_started = 1; initscr(); old_SIGINT = signal(SIGINT, die); old_SIGTERM = signal(SIGTERM, die); @@ -2105,18 +2196,23 @@ void do_curses_fdisk(void) draw_screen(); while (!done) { - (void)draw_cursor(0); + char *s; - if (p_info[cur_part].id == FREE_SPACE) - command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, "hnpquW", - MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); - else if (p_info[cur_part].id > 0) - command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, "bdhmpqtuW", - MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); - else - command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, "hpquW", - MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); + (void)draw_cursor(0); + if (p_info[cur_part].id == FREE_SPACE) { + s = ((opentype == O_RDWR) ? "hnpquW" : "hnpqu"); + command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, + s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); + } else if (p_info[cur_part].id > 0) { + s = ((opentype == O_RDWR) ? "bdhmpqtuW" : "bdhmpqtu"); + command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, + s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); + } else { + s = ((opentype == O_RDWR) ? "hpquW" : "hpqu"); + command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, + s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); + } switch ( command ) { case 'B': case 'b': @@ -2225,30 +2321,34 @@ void do_curses_fdisk(void) } } - signal(SIGINT, old_SIGINT); - signal(SIGTERM, old_SIGTERM); - mvcur(0, COLS-1, LINES-1, 0); - nl(); - endwin(); - fdexit(0); + die_x(0); } void copyright(void) { - fprintf(stderr, "Copyright (C) 1994 Kevin E. Martin\n"); + fprintf(stderr, "Copyright (C) 1994-1997 Kevin E. Martin & aeb\n"); } void usage(char *prog_name) { - fprintf(stderr, - "%s: [-avz] [-c # cylinders] [-h # heads] [-s # sectors/track]\n", - prog_name); - fprintf(stderr, - "[ -P opt ] device\n"); + fprintf(stderr, "\nUsage:\n"); + fprintf(stderr, "Print version:\n"); + fprintf(stderr, "\t%s -v\n", prog_name); + fprintf(stderr, "Print partition table:\n"); + fprintf(stderr, "\t%s -P {r|s|t} [options] device\n", prog_name); + fprintf(stderr, "Interactive use:\n"); + fprintf(stderr, "\t%s [options] device\n", prog_name); + fprintf(stderr, " +Options: +-a: Use arrow instead of highlighting; +-z: Start with a zero partition table, instead of reading the pt from disk; +-c C -h H -s S: Override the kernel's idea of the number of cylinders, + the number of heads and the number of sectors/track.\n\n"); + copyright(); } -void main(int argc, char **argv) +int main(int argc, char **argv) { char c; int i, len; @@ -2315,7 +2415,7 @@ void main(int argc, char **argv) else if (argc-optind != 0) { usage(argv[0]); exit(1); - } else if ((fd = open(DEFAULT_DEVICE, O_RDWR)) < 0) + } else if ((fd = open(DEFAULT_DEVICE, O_RDONLY)) < 0) disk_device = ALTERNATE_DEVICE; else close(fd); @@ -2329,4 +2429,5 @@ void main(int argc, char **argv) print_part_table(); } else do_curses_fdisk(); + return 0; } diff --git a/disk-utils/fdformat.c b/disk-utils/fdformat.c index 8b08535a6..46b9e2320 100644 --- a/disk-utils/fdformat.c +++ b/disk-utils/fdformat.c @@ -7,6 +7,7 @@ #include <unistd.h> #include <stdlib.h> #include <sys/stat.h> +#include <sys/ioctl.h> #include <linux/fd.h> #include <linux/fs.h> @@ -28,13 +29,15 @@ static void format_disk(char *name) for (track = 0; track < param.track; track++) { descr.track = track; descr.head = 0; - if (ioctl(ctrl,FDFMTTRK,(int) &descr) < 0) PERROR("\nioctl(FDFMTTRK)"); + if (ioctl(ctrl,FDFMTTRK,(long) &descr) < 0) + PERROR("\nioctl(FDFMTTRK)"); + printf("%3d\b\b\b",track); fflush(stdout); if (param.head == 2) { descr.head = 1; - if (ioctl(ctrl,FDFMTTRK,(int) &descr) < 0) - PERROR("\nioctl(FDFMTTRK)"); + if (ioctl(ctrl,FDFMTTRK,(long) &descr) < 0) + PERROR("\nioctl(FDFMTTRK)"); } } if (ioctl(ctrl,FDFMTEND,NULL) < 0) PERROR("\nioctl(FDFMTEND)"); @@ -72,7 +75,7 @@ static void usage(char *name) { char *this; - if (this = strrchr(name,'/')) name = this+1; + if ((this = strrchr(name,'/')) != NULL) name = this+1; fprintf(stderr,"usage: %s [ -n ] device\n",name); exit(1); } @@ -100,7 +103,8 @@ int main(int argc,char **argv) } if (access(argv[1],W_OK) < 0) PERROR(argv[1]); if ((ctrl = open(argv[1],3)) < 0) PERROR(argv[1]); - if (ioctl(ctrl,FDGETPRM,(int) ¶m) < 0) PERROR("ioctl(FDGETPRM)"); + if (ioctl(ctrl,FDGETPRM,(long) ¶m) < 0) + PERROR("Could not determine current format type"); printf("%sle-sided, %d tracks, %d sec/track. Total capacity %d kB.\n", param.head ? "Doub" : "Sing",param.track,param.sect,param.size >> 1); format_disk(argv[1]); diff --git a/disk-utils/fdisk.8 b/disk-utils/fdisk.8 index 395e9c71d..29d56c40b 100644 --- a/disk-utils/fdisk.8 +++ b/disk-utils/fdisk.8 @@ -101,7 +101,7 @@ if you use the .B dd command, since a small typo can make all of the data on your disk useless. -For best resutls, you should always use an OS-specific partition table +For best results, you should always use an OS-specific partition table program. For example, you should make DOS partitions with the DOS FDISK program and Linux partitions with the Linux fdisk or Linux cfdisk program. diff --git a/disk-utils/fdisk.c b/disk-utils/fdisk.c index f3455fa5f..95b958d82 100644 --- a/disk-utils/fdisk.c +++ b/disk-utils/fdisk.c @@ -225,7 +225,7 @@ void menu(void) puts("Command action\n" " a toggle a bootable flag\n" " b edit bsd disklabel\n" /* bf */ - " c toggle the dos compatiblity flag\n" + " c toggle the dos compatibility flag\n" " d delete a partition\n" " l list known partition types\n" " m print this menu\n" @@ -449,7 +449,7 @@ void read_extended(struct partition *p) } } -void get_boot(void) +int get_boot(void) { int i; struct hd_geometry geometry; @@ -464,6 +464,7 @@ void get_boot(void) } if (SECTOR_SIZE != read(fd, buffer, SECTOR_SIZE)) fatal(unable_to_read); + #ifdef HDIO_REQ if (!ioctl(fd, HDIO_REQ, &geometry)) { #else @@ -479,6 +480,10 @@ void get_boot(void) else update_units(); warn_geometry(); + if (*(unsigned short *) (0x1fe + buffer) != 0xAA55) { + return 0; /* not a valid partition table */ + } + for (i = 0; i < 4; i++) if(part_table[i]->sys_ind == EXTENDED) if (partitions != 4) @@ -493,6 +498,8 @@ void get_boot(void) *table_check(buffers[i]), i + 1); changed[i] = 1; } + + return 1; } int read_line(void) @@ -587,6 +594,7 @@ uint read_int(uint low, uint dflt, uint high, enum offset base, char *mesg) case lower: i += low; break; case upper: i += high; break; case deflt: i += dflt; break; + case ignore: } } else @@ -805,12 +813,12 @@ static void check_consistency(struct partition *p, int partition) return; /* do not check extended partitions */ /* physical beginning c, h, s */ - pbc = p->cyl & 0xff | (p->sector << 2) & 0x300; + 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; + pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300); peh = p->end_head; pes = p->end_sector & 0x3f; @@ -902,7 +910,7 @@ void x_list_table(int extend) 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]) { + 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), @@ -987,9 +995,8 @@ void verify(void) 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])) { + 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] ? @@ -1021,7 +1028,7 @@ void verify(void) 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) + else if ((total = heads * sectors * cylinders - total) != 0) printf("%d unallocated sectors\n", total); } @@ -1219,11 +1226,10 @@ void write_table(void) printf("The partition table has been altered!\n\n"); - printf("Calling ioctl() to re-read partition table.\n" - "(Reboot to ensure the partition table has been updated.)\n"); + printf("Calling ioctl() to re-read partition table.\n"); sync(); sleep(2); - if (i = ioctl(fd, BLKRRPART)) { + if ((i = ioctl(fd, BLKRRPART)) != 0) { error = errno; } else { /* some kernel versions (1.2.x) seem to have trouble @@ -1231,7 +1237,7 @@ void write_table(void) twice, the second time works. - biro@yggdrasil.com */ sync(); sleep(2); - if(i = ioctl(fd, BLKRRPART)) + if((i = ioctl(fd, BLKRRPART)) != 0) error = errno; } @@ -1352,22 +1358,27 @@ void xselect(void) void try(char *device) { disk_device = device; - if (!setjmp(listingbuf)) + if (!setjmp(listingbuf)) { if ((fd = open(disk_device, type_open)) >= 0) { - close(fd); - get_boot(); - list_table(); - if (partitions > 4) + if (get_boot()) { + close(fd); + list_table(); + if (partitions > 4) delete_partition(ext_index); - } else { + } else { + btrydev(device); + close(fd); + } + } 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); - exit(1); - } - } + if(errno == EACCES) { + fprintf(stderr, "Cannot open %s\n", device); + exit(1); + } + } + } } void main(int argc, char **argv) diff --git a/disk-utils/fdisk.h b/disk-utils/fdisk.h index 4f23fd8a3..89510031a 100644 --- a/disk-utils/fdisk.h +++ b/disk-utils/fdisk.h @@ -45,3 +45,4 @@ extern char *const str_units(void); /* prototypes for fdisklabel.c */ extern void bselect(void); +extern void btrydev (char * dev); diff --git a/disk-utils/fdisklabel.c b/disk-utils/fdisklabel.c index 5fbf67a4c..a6b5ecc4d 100644 --- a/disk-utils/fdisklabel.c +++ b/disk-utils/fdisklabel.c @@ -55,38 +55,46 @@ #define DKTYPENAMES #include "fdisklabel.h" -static void bsd_delete_part (void); -static void bsd_new_part (void); -static void bsd_print_disklabel (int show_all); -static void bsd_write_disklabel (void); -static int bsd_create_disklabel (void); -static void bsd_edit_disklabel (void); -static void bsd_write_bootstrap (void); -static void bsd_change_fstype (void); -static int bsd_get_part_index (int max); -static int bsd_check_new_partition (int *i); -static void bsd_list_types (void); -static u_short bsd_dkcksum (struct disklabel *lp); -static int bsd_initlabel (struct partition *p, struct disklabel *d, int pindex); -static int bsd_readlabel (struct partition *p, struct disklabel *d); -static int bsd_writelabel (struct partition *p, struct disklabel *d); +static void xbsd_delete_part (void); +static void xbsd_new_part (void); +static void xbsd_print_disklabel (int show_all); +static void xbsd_write_disklabel (void); +static int xbsd_create_disklabel (void); +static void xbsd_edit_disklabel (void); +static void xbsd_write_bootstrap (void); +static void xbsd_change_fstype (void); +static int xbsd_get_part_index (int max); +static int xbsd_check_new_partition (int *i); +static void xbsd_list_types (void); +static u_short xbsd_dkcksum (struct xbsd_disklabel *lp); +static int xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex); +static int xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d); +static int xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d); static void sync_disks (void); #if defined (i386) -static int bsd_translate_fstype (int linux_type); -static void bsd_link_part (void); +static int xbsd_translate_fstype (int linux_type); +static void xbsd_link_part (void); #endif #if defined (__alpha__) void alpha_bootblock_checksum (char *boot); #endif -static struct disklabel bsd_dlabel; +static struct xbsd_disklabel xbsd_dlabel; static char buffer[BSD_BBSIZE]; #if defined (i386) -static struct partition *bsd_part; -static int bsd_part_index; +static struct partition *xbsd_part; +static int xbsd_part_index; #endif void +btrydev (char * dev) { + if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0) + return; + printf("\nBSD label for device: %s\n", dev); + xbsd_print_disklabel (0); +} + +void bmenu (void) { puts ("Command action\n" @@ -119,18 +127,18 @@ bselect (void) for (t=0; t<4; t++) if (part_table[t] -> sys_ind == NETBSD_PARTITION) { - bsd_part = part_table[t]; - bsd_part_index = t; - if (bsd_part -> start_sect == 0) + xbsd_part = part_table[t]; + xbsd_part_index = t; + if (xbsd_part -> start_sect == 0) { fprintf (stderr, "Partition %s%d has invalid starting sector 0.\n", disk_device, t+1); return; } printf ("Reading disklabel of %s%d at sector %d.\n", - disk_device, t+1, bsd_part -> start_sect + BSD_LABELSECTOR); - if (bsd_readlabel (bsd_part, &bsd_dlabel) == 0) - if (bsd_create_disklabel () == 0) + disk_device, t+1, xbsd_part -> start_sect + BSD_LABELSECTOR); + if (xbsd_readlabel (xbsd_part, &xbsd_dlabel) == 0) + if (xbsd_create_disklabel () == 0) return; break; } @@ -143,8 +151,8 @@ bselect (void) #elif defined (__alpha__) - if (bsd_readlabel (NULL, &bsd_dlabel) == 0) - if (bsd_create_disklabel () == 0) + if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0) + if (xbsd_create_disklabel () == 0) exit ( EXIT_SUCCESS ); #endif @@ -155,40 +163,40 @@ bselect (void) switch (tolower (read_char ("BSD disklabel command (m for help): "))) { case 'd': - bsd_delete_part (); + xbsd_delete_part (); break; case 'e': - bsd_edit_disklabel (); + xbsd_edit_disklabel (); break; case 'i': - bsd_write_bootstrap (); + xbsd_write_bootstrap (); break; case 'l': - bsd_list_types (); + xbsd_list_types (); break; case 'n': - bsd_new_part (); + xbsd_new_part (); break; case 'p': - bsd_print_disklabel (0); + xbsd_print_disklabel (0); break; case 'q': close (fd); exit ( EXIT_SUCCESS ); case 's': - bsd_print_disklabel (1); + xbsd_print_disklabel (1); break; case 't': - bsd_change_fstype (); + xbsd_change_fstype (); break; case 'w': - bsd_write_disklabel (); + xbsd_write_disklabel (); break; #if defined (i386) case 'r': return; case 'x': - bsd_link_part (); + xbsd_link_part (); break; #endif default: @@ -199,35 +207,35 @@ bselect (void) } static void -bsd_delete_part (void) +xbsd_delete_part (void) { int i; - i = bsd_get_part_index (bsd_dlabel.d_npartitions); - bsd_dlabel.d_partitions[i].p_size = 0; - bsd_dlabel.d_partitions[i].p_offset = 0; - bsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED; - if (bsd_dlabel.d_npartitions == i + 1) - while (bsd_dlabel.d_partitions[bsd_dlabel.d_npartitions-1].p_size == 0) - bsd_dlabel.d_npartitions--; + i = xbsd_get_part_index (xbsd_dlabel.d_npartitions); + xbsd_dlabel.d_partitions[i].p_size = 0; + xbsd_dlabel.d_partitions[i].p_offset = 0; + xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED; + if (xbsd_dlabel.d_npartitions == i + 1) + while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0) + xbsd_dlabel.d_npartitions--; } static void -bsd_new_part (void) +xbsd_new_part (void) { uint begin, end; char mesg[48]; int i; - if (!bsd_check_new_partition (&i)) + if (!xbsd_check_new_partition (&i)) return; #if defined (i386) - begin = bsd_part -> start_sect; - end = begin + bsd_part -> nr_sects - 1; + begin = xbsd_part -> start_sect; + end = begin + xbsd_part -> nr_sects - 1; #elif defined (__alpha__) begin = 0; - end = bsd_dlabel.d_secperunit; + end = xbsd_dlabel.d_secperunit; #endif sprintf (mesg, "First %s", str_units()); @@ -241,32 +249,32 @@ bsd_new_part (void) begin = (begin - 1) * display_factor; end = end * display_factor - 1; } - bsd_dlabel.d_partitions[i].p_size = end - begin + 1; - bsd_dlabel.d_partitions[i].p_offset = begin; - bsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED; + xbsd_dlabel.d_partitions[i].p_size = end - begin + 1; + xbsd_dlabel.d_partitions[i].p_offset = begin; + xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED; } static void -bsd_print_disklabel (int show_all) +xbsd_print_disklabel (int show_all) { - struct disklabel *lp = &bsd_dlabel; - struct bsd_partition *pp; + struct xbsd_disklabel *lp = &xbsd_dlabel; + struct xbsd_partition *pp; FILE *f = stdout; int i, j; if (show_all) { #if defined (i386) - fprintf(f, "# %s%d:\n", disk_device, bsd_part_index+1); + fprintf(f, "# %s%d:\n", disk_device, xbsd_part_index+1); #elif defined (__alpha__) fprintf(f, "# %s:\n", disk_device); #endif if ((unsigned) lp->d_type < BSD_DKMAXTYPES) - fprintf(f, "type: %s\n", bsd_dktypenames[lp->d_type]); + fprintf(f, "type: %s\n", xbsd_dktypenames[lp->d_type]); else fprintf(f, "type: %d\n", lp->d_type); - fprintf(f, "disk: %.*s\n", sizeof(lp->d_typename), lp->d_typename); - fprintf(f, "label: %.*s\n", sizeof(lp->d_packname), lp->d_packname); + fprintf(f, "disk: %.*s\n", (int) sizeof(lp->d_typename), lp->d_typename); + fprintf(f, "label: %.*s\n", (int) sizeof(lp->d_packname), lp->d_packname); fprintf(f, "flags:"); if (lp->d_flags & BSD_D_REMOVABLE) fprintf(f, " removable"); @@ -275,17 +283,19 @@ bsd_print_disklabel (int show_all) if (lp->d_flags & BSD_D_BADSECT) fprintf(f, " badsect"); fprintf(f, "\n"); - fprintf(f, "bytes/sector: %d\n", lp->d_secsize); - fprintf(f, "sectors/track: %d\n", lp->d_nsectors); - fprintf(f, "tracks/cylinder: %d\n", lp->d_ntracks); - fprintf(f, "sectors/cylinder: %d\n", lp->d_secpercyl); - fprintf(f, "cylinders: %d\n", lp->d_ncylinders); + /* On various machines the fields of *lp are short/int/long */ + /* In order to avoid problems, we cast them all to long. */ + fprintf(f, "bytes/sector: %ld\n", (long) lp->d_secsize); + fprintf(f, "sectors/track: %ld\n", (long) lp->d_nsectors); + fprintf(f, "tracks/cylinder: %ld\n", (long) lp->d_ntracks); + fprintf(f, "sectors/cylinder: %ld\n", (long) lp->d_secpercyl); + fprintf(f, "cylinders: %ld\n", (long) lp->d_ncylinders); fprintf(f, "rpm: %d\n", lp->d_rpm); fprintf(f, "interleave: %d\n", lp->d_interleave); fprintf(f, "trackskew: %d\n", lp->d_trackskew); fprintf(f, "cylinderskew: %d\n", lp->d_cylskew); - fprintf(f, "headswitch: %d\t\t# milliseconds\n", lp->d_headswitch); - fprintf(f, "track-to-track seek: %d\t# milliseconds\n", lp->d_trkseek); + fprintf(f, "headswitch: %ld\t\t# milliseconds\n", (long) lp->d_headswitch); + fprintf(f, "track-to-track seek: %ld\t# milliseconds\n", (long) lp->d_trkseek); fprintf(f, "drivedata: "); for (i = NDDATA - 1; i >= 0; i--) if (lp->d_drivedata[i]) @@ -293,29 +303,29 @@ bsd_print_disklabel (int show_all) if (i < 0) i = 0; for (j = 0; j <= i; j++) - fprintf(f, "%d ", lp->d_drivedata[j]); + fprintf(f, "%ld ", (long) lp->d_drivedata[j]); } fprintf (f, "\n%d partitions:\n", lp->d_npartitions); fprintf (f, "# size offset fstype [fsize bsize cpg]\n"); pp = lp->d_partitions; for (i = 0; i < lp->d_npartitions; i++, pp++) { if (pp->p_size) { - fprintf(f, " %c: %8d %8d ", 'a' + i, - pp->p_size, pp->p_offset); + fprintf(f, " %c: %8ld %8ld ", 'a' + i, + (long) pp->p_size, (long) pp->p_offset); if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES) - fprintf(f, "%8.8s", bsd_fstypes[pp->p_fstype].name); + fprintf(f, "%8.8s", xbsd_fstypes[pp->p_fstype].name); else fprintf(f, "%8x", pp->p_fstype); switch (pp->p_fstype) { case BSD_FS_UNUSED: - fprintf(f, " %5d %5d %5.5s ", - pp->p_fsize, pp->p_fsize * pp->p_frag, ""); + fprintf(f, " %5ld %5ld %5.5s ", + (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, ""); break; case BSD_FS_BSDFFS: - fprintf(f, " %5d %5d %5d ", - pp->p_fsize, pp->p_fsize * pp->p_frag, + fprintf(f, " %5ld %5ld %5d ", + (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, pp->p_cpg); break; @@ -323,7 +333,7 @@ bsd_print_disklabel (int show_all) fprintf(f, "%20.20s", ""); break; } - fprintf(f, "\t# (Cyl. %4d", + fprintf(f, "\t# (Cyl. %4ld", (long) #if 0 pp->p_offset / lp->d_secpercyl); /* differs from Linux fdisk */ #else @@ -333,8 +343,8 @@ bsd_print_disklabel (int show_all) putc('*', f); else putc(' ', f); - fprintf(f, "- %d", - (pp->p_offset + + fprintf(f, "- %ld", + (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / #if 0 lp->d_secpercyl - 1); /* differs from Linux fdisk */ @@ -349,25 +359,25 @@ bsd_print_disklabel (int show_all) } static void -bsd_write_disklabel (void) +xbsd_write_disklabel (void) { #if defined (i386) - printf ("Writing disklabel to %s%d.\n", disk_device, bsd_part_index+1); - bsd_writelabel (bsd_part, &bsd_dlabel); + printf ("Writing disklabel to %s%d.\n", disk_device, xbsd_part_index+1); + xbsd_writelabel (xbsd_part, &xbsd_dlabel); #elif defined (__alpha__) printf ("Writing disklabel to %s.\n", disk_device); - bsd_writelabel (NULL, &bsd_dlabel); + xbsd_writelabel (NULL, &xbsd_dlabel); #endif } static int -bsd_create_disklabel (void) +xbsd_create_disklabel (void) { char c; #if defined (i386) fprintf (stderr, "%s%d contains no disklabel.\n", - disk_device, bsd_part_index+1); + disk_device, xbsd_part_index+1); #elif defined (__alpha__) fprintf (stderr, "%s contains no disklabel.\n", disk_device); #endif @@ -376,12 +386,12 @@ bsd_create_disklabel (void) if ((c = tolower (read_char ("Do you want to create a disklabel? (y/n) "))) == 'y') { #if defined (i386) - if (bsd_initlabel (bsd_part, &bsd_dlabel, bsd_part_index) == 1) + if (xbsd_initlabel (xbsd_part, &xbsd_dlabel, xbsd_part_index) == 1) #elif defined (__alpha__) - if (bsd_initlabel (NULL, &bsd_dlabel, 0) == 1) + if (xbsd_initlabel (NULL, &xbsd_dlabel, 0) == 1) #endif { - bsd_print_disklabel (1); + xbsd_print_disklabel (1); return 1; } else @@ -405,11 +415,11 @@ edit_int (int def, char *mesg) } static void -bsd_edit_disklabel (void) +xbsd_edit_disklabel (void) { - struct disklabel *d; + struct xbsd_disklabel *d; - d = &bsd_dlabel; + d = &xbsd_dlabel; #ifdef __alpha__ d -> d_secsize = (u_long) edit_int ((u_long) d -> d_secsize ,"bytes/sector"); @@ -439,7 +449,7 @@ bsd_edit_disklabel (void) } static int -bsd_get_bootstrap (char *path, void *ptr, int size) +xbsd_get_bootstrap (char *path, void *ptr, int size) { int fd; @@ -460,16 +470,16 @@ bsd_get_bootstrap (char *path, void *ptr, int size) } static void -bsd_write_bootstrap (void) +xbsd_write_bootstrap (void) { char *bootdir = BSD_LINUX_BOOTDIR; char path[MAXPATHLEN]; char *dkbasename; - struct disklabel dl; + struct xbsd_disklabel dl; char *d, *p, *e; int sector; - if (bsd_dlabel.d_type == BSD_DTYPE_SCSI) + if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI) dkbasename = "sd"; else dkbasename = "wd"; @@ -481,22 +491,22 @@ bsd_write_bootstrap (void) dkbasename = line_ptr; } sprintf (path, "%s/%sboot", bootdir, dkbasename); - if (!bsd_get_bootstrap (path, buffer, (int) bsd_dlabel.d_secsize)) + if (!xbsd_get_bootstrap (path, buffer, (int) xbsd_dlabel.d_secsize)) return; - /* We need a backup of the disklabel (bsd_dlabel might have changed). */ + /* We need a backup of the disklabel (xbsd_dlabel might have changed). */ d = &buffer[BSD_LABELSECTOR * SECTOR_SIZE]; - bcopy (d, &dl, sizeof (struct disklabel)); + bcopy (d, &dl, sizeof (struct xbsd_disklabel)); /* The disklabel will be overwritten by 0's from bootxx anyway */ - bzero (d, sizeof (struct disklabel)); + bzero (d, sizeof (struct xbsd_disklabel)); sprintf (path, "%s/boot%s", bootdir, dkbasename); - if (!bsd_get_bootstrap (path, &buffer[bsd_dlabel.d_secsize], - (int) bsd_dlabel.d_bbsize - bsd_dlabel.d_secsize)) + if (!xbsd_get_bootstrap (path, &buffer[xbsd_dlabel.d_secsize], + (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize)) return; - e = d + sizeof (struct disklabel); + e = d + sizeof (struct xbsd_disklabel); for (p=d; p < e; p++) if (*p) { @@ -504,10 +514,10 @@ bsd_write_bootstrap (void) exit ( EXIT_FAILURE ); } - bcopy (&dl, d, sizeof (struct disklabel)); + bcopy (&dl, d, sizeof (struct xbsd_disklabel)); #if defined (i386) - sector = bsd_part -> start_sect; + sector = xbsd_part -> start_sect; #elif defined (__alpha__) sector = 0; alpha_bootblock_checksum (buffer); @@ -519,7 +529,7 @@ bsd_write_bootstrap (void) fatal (unable_to_write); #if defined (i386) - printf ("Bootstrap installed on %s%d.\n", disk_device, bsd_part_index+1); + printf ("Bootstrap installed on %s%d.\n", disk_device, xbsd_part_index+1); #elif defined (__alpha__) printf ("Bootstrap installed on %s.\n", disk_device); #endif @@ -528,16 +538,16 @@ bsd_write_bootstrap (void) } static void -bsd_change_fstype (void) +xbsd_change_fstype (void) { int i; - i = bsd_get_part_index (bsd_dlabel.d_npartitions); - bsd_dlabel.d_partitions[i].p_fstype = read_hex (bsd_fstypes, BSD_FSMAXTYPES); + i = xbsd_get_part_index (xbsd_dlabel.d_npartitions); + xbsd_dlabel.d_partitions[i].p_fstype = read_hex (xbsd_fstypes, BSD_FSMAXTYPES); } static int -bsd_get_part_index (int max) +xbsd_get_part_index (int max) { char prompt[40]; char l; @@ -550,14 +560,14 @@ bsd_get_part_index (int max) } static int -bsd_check_new_partition (int *i) +xbsd_check_new_partition (int *i) { int t; - if (bsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) + if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) { for (t=0; t < BSD_MAXPARTITIONS; t++) - if (bsd_dlabel.d_partitions[t].p_size == 0) + if (xbsd_dlabel.d_partitions[t].p_size == 0) break; if (t == BSD_MAXPARTITIONS) @@ -566,12 +576,12 @@ bsd_check_new_partition (int *i) return 0; } } - *i = bsd_get_part_index (BSD_MAXPARTITIONS); + *i = xbsd_get_part_index (BSD_MAXPARTITIONS); - if (*i >= bsd_dlabel.d_npartitions) - bsd_dlabel.d_npartitions = (*i) + 1; + if (*i >= xbsd_dlabel.d_npartitions) + xbsd_dlabel.d_npartitions = (*i) + 1; - if (bsd_dlabel.d_partitions[*i].p_size != 0) + if (xbsd_dlabel.d_partitions[*i].p_size != 0) { fprintf (stderr, "This partition already exists.\n"); return 0; @@ -580,13 +590,13 @@ bsd_check_new_partition (int *i) } static void -bsd_list_types (void) +xbsd_list_types (void) { - list_types (bsd_fstypes, BSD_FSMAXTYPES); + list_types (xbsd_fstypes, BSD_FSMAXTYPES); } static u_short -bsd_dkcksum (struct disklabel *lp) +xbsd_dkcksum (struct xbsd_disklabel *lp) { register u_short *start, *end; register u_short sum = 0; @@ -599,17 +609,17 @@ bsd_dkcksum (struct disklabel *lp) } static int -bsd_initlabel (struct partition *p, struct disklabel *d, int pindex) +xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex) { struct hd_geometry geometry; - struct bsd_partition *pp; + struct xbsd_partition *pp; if (ioctl (fd, HDIO_GETGEO, &geometry) == -1) { perror ("ioctl"); return 0; } - bzero (d, sizeof (struct disklabel)); + bzero (d, sizeof (struct xbsd_disklabel)); d -> d_magic = BSD_DISKMAGIC; @@ -667,7 +677,7 @@ bsd_initlabel (struct partition *p, struct disklabel *d, int pindex) } static int -bsd_readlabel (struct partition *p, struct disklabel *d) +xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d) { int t, sector; @@ -683,7 +693,7 @@ bsd_readlabel (struct partition *p, struct disklabel *d) fatal (unable_to_read); bcopy (&buffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET], - d, sizeof (struct disklabel)); + d, sizeof (struct xbsd_disklabel)); for (t = d -> d_npartitions; t < BSD_MAXPARTITIONS; t++) { @@ -701,7 +711,7 @@ bsd_readlabel (struct partition *p, struct disklabel *d) } static int -bsd_writelabel (struct partition *p, struct disklabel *d) +xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d) { int sector; @@ -712,13 +722,13 @@ bsd_writelabel (struct partition *p, struct disklabel *d) #endif d -> d_checksum = 0; - d -> d_checksum = bsd_dkcksum (d); + d -> d_checksum = xbsd_dkcksum (d); /* This is necessary if we want to write the bootstrap later, otherwise we'd write the old disklabel with the bootstrap. */ bcopy (d, &buffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET], - sizeof (struct disklabel)); + sizeof (struct xbsd_disklabel)); #if defined (__alpha__) && BSD_LABELSECTOR == 0 alpha_bootblock_checksum (buffer); @@ -729,7 +739,7 @@ bsd_writelabel (struct partition *p, struct disklabel *d) #else if (ext2_llseek (fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1) fatal (unable_to_seek); - if (sizeof (struct disklabel) != write (fd, d, sizeof (struct disklabel))) + if (sizeof (struct xbsd_disklabel) != write (fd, d, sizeof (struct xbsd_disklabel))) fatal (unable_to_write); #endif @@ -748,7 +758,7 @@ sync_disks (void) #if defined (i386) static int -bsd_translate_fstype (int linux_type) +xbsd_translate_fstype (int linux_type) { switch (linux_type) { @@ -767,24 +777,23 @@ bsd_translate_fstype (int linux_type) } static void -bsd_link_part (void) +xbsd_link_part (void) { int k, i; k = get_partition (1, partitions); - if (!bsd_check_new_partition (&i)) + if (!xbsd_check_new_partition (&i)) return; - bsd_dlabel.d_partitions[i].p_size = part_table[k] -> nr_sects; - bsd_dlabel.d_partitions[i].p_offset = part_table[k] -> start_sect; - bsd_dlabel.d_partitions[i].p_fstype = - bsd_translate_fstype (part_table[k] -> sys_ind); + xbsd_dlabel.d_partitions[i].p_size = part_table[k] -> nr_sects; + xbsd_dlabel.d_partitions[i].p_offset = part_table[k] -> start_sect; + xbsd_dlabel.d_partitions[i].p_fstype = + xbsd_translate_fstype (part_table[k] -> sys_ind); } #endif #if defined (__alpha__) -typedef unsigned long long u_int64_t; void alpha_bootblock_checksum (char *boot) diff --git a/disk-utils/fdisklabel.h b/disk-utils/fdisklabel.h index 841046bb8..d007b34b2 100644 --- a/disk-utils/fdisklabel.h +++ b/disk-utils/fdisklabel.h @@ -31,8 +31,14 @@ * SUCH DAMAGE. */ -#define BSD_DISKMAGIC ((u_long) 0x82564557) +#ifndef BSD_DISKMAGIC /* perhaps from <linux/genhd.h> */ +#define BSD_DISKMAGIC ((__u32) 0x82564557) +#endif + +#ifndef BSD_MAXPARTITIONS #define BSD_MAXPARTITIONS 8 +#endif + #define BSD_LINUX_BOOTDIR "/usr/ucb/mdec" #if defined (i386) @@ -41,62 +47,40 @@ #define BSD_BBSIZE 8192 /* size of boot area, with label */ #define BSD_SBSIZE 8192 /* max size of fs superblock */ #elif defined (__alpha__) -#error LABELSECTOR, LABELOFFSET, BBSIZE & SBSIZE are undefined for __alpha__ #define BSD_LABELSECTOR 0 -#define BSD_LABELOFFSET 0 -#define BSD_BBSIZE 0 -#define BSD_SBSIZE 0 +#define BSD_LABELOFFSET 64 +#define BSD_BBSIZE 8192 +#define BSD_SBSIZE 8192 #else #error unknown architecture #endif -struct disklabel { - u_long d_magic; /* the magic number */ - short d_type; /* drive type */ - short d_subtype; /* controller/d_type specific */ +struct xbsd_disklabel { + __u32 d_magic; /* the magic number */ + __s16 d_type; /* drive type */ + __s16 d_subtype; /* controller/d_type specific */ char d_typename[16]; /* type name, e.g. "eagle" */ - /* - * d_packname contains the pack identifier and is returned when - * the disklabel is read off the disk or in-core copy. - * d_boot0 and d_boot1 are the (optional) names of the - * primary (block 0) and secondary (block 1-15) bootstraps - * as found in /usr/mdec. These are returned when using - * getdiskbyname(3) to retrieve the values from /etc/disktab. - */ -#if defined(KERNEL) || defined(STANDALONE) char d_packname[16]; /* pack identifier */ -#else - union { - char un_d_packname[16]; /* pack identifier */ - struct { - char *un_d_boot0; /* primary bootstrap name */ - char *un_d_boot1; /* secondary bootstrap name */ - } un_b; - } d_un; -#define d_packname d_un.un_d_packname -#define d_boot0 d_un.un_b.un_d_boot0 -#define d_boot1 d_un.un_b.un_d_boot1 -#endif /* ! KERNEL or STANDALONE */ /* disk geometry: */ - u_long d_secsize; /* # of bytes per sector */ - u_long d_nsectors; /* # of data sectors per track */ - u_long d_ntracks; /* # of tracks per cylinder */ - u_long d_ncylinders; /* # of data cylinders per unit */ - u_long d_secpercyl; /* # of data sectors per cylinder */ - u_long d_secperunit; /* # of data sectors per unit */ + __u32 d_secsize; /* # of bytes per sector */ + __u32 d_nsectors; /* # of data sectors per track */ + __u32 d_ntracks; /* # of tracks per cylinder */ + __u32 d_ncylinders; /* # of data cylinders per unit */ + __u32 d_secpercyl; /* # of data sectors per cylinder */ + __u32 d_secperunit; /* # of data sectors per unit */ /* * Spares (bad sector replacements) below * are not counted in d_nsectors or d_secpercyl. * Spare sectors are assumed to be physical sectors * which occupy space at the end of each track and/or cylinder. */ - u_short d_sparespertrack; /* # of spare sectors per track */ - u_short d_sparespercyl; /* # of spare sectors per cylinder */ + __u16 d_sparespertrack; /* # of spare sectors per track */ + __u16 d_sparespercyl; /* # of spare sectors per cylinder */ /* * Alternate cylinders include maintenance, replacement, * configuration description areas, etc. */ - u_long d_acylinders; /* # of alt. cylinders per unit */ + __u32 d_acylinders; /* # of alt. cylinders per unit */ /* hardware characteristics: */ /* @@ -115,30 +99,30 @@ struct disklabel { * Finally, d_cylskew is the offset of sector 0 on cylinder N * relative to sector 0 on cylinder N-1. */ - u_short d_rpm; /* rotational speed */ - u_short d_interleave; /* hardware sector interleave */ - u_short d_trackskew; /* sector 0 skew, per track */ - u_short d_cylskew; /* sector 0 skew, per cylinder */ - u_long d_headswitch; /* head switch time, usec */ - u_long d_trkseek; /* track-to-track seek, usec */ - u_long d_flags; /* generic flags */ + __u16 d_rpm; /* rotational speed */ + __u16 d_interleave; /* hardware sector interleave */ + __u16 d_trackskew; /* sector 0 skew, per track */ + __u16 d_cylskew; /* sector 0 skew, per cylinder */ + __u32 d_headswitch; /* head switch time, usec */ + __u32 d_trkseek; /* track-to-track seek, usec */ + __u32 d_flags; /* generic flags */ #define NDDATA 5 - u_long d_drivedata[NDDATA]; /* drive-type specific information */ + __u32 d_drivedata[NDDATA]; /* drive-type specific information */ #define NSPARE 5 - u_long d_spare[NSPARE]; /* reserved for future use */ - u_long d_magic2; /* the magic number (again) */ - u_short d_checksum; /* xor of data incl. partitions */ + __u32 d_spare[NSPARE]; /* reserved for future use */ + __u32 d_magic2; /* the magic number (again) */ + __u16 d_checksum; /* xor of data incl. partitions */ /* filesystem and partition information: */ - u_short d_npartitions; /* number of partitions in following */ - u_long d_bbsize; /* size of boot area at sn0, bytes */ - u_long d_sbsize; /* max size of fs superblock, bytes */ - struct bsd_partition { /* the partition table */ - u_long p_size; /* number of sectors in partition */ - u_long p_offset; /* starting sector */ - u_long p_fsize; /* filesystem basic fragment size */ - u_char p_fstype; /* filesystem type, see below */ - u_char p_frag; /* filesystem fragments per block */ - u_short p_cpg; /* filesystem cylinders per group */ + __u16 d_npartitions; /* number of partitions in following */ + __u32 d_bbsize; /* size of boot area at sn0, bytes */ + __u32 d_sbsize; /* max size of fs superblock, bytes */ + struct xbsd_partition { /* the partition table */ + __u32 p_size; /* number of sectors in partition */ + __u32 p_offset; /* starting sector */ + __u32 p_fsize; /* filesystem basic fragment size */ + __u8 p_fstype; /* filesystem type, see below */ + __u8 p_frag; /* filesystem fragments per block */ + __u16 p_cpg; /* filesystem cylinders per group */ } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */ }; @@ -159,7 +143,7 @@ struct disklabel { #define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */ #ifdef DKTYPENAMES -static char *bsd_dktypenames[] = { +static char *xbsd_dktypenames[] = { "unknown", "SMD", "MSCP", @@ -173,7 +157,7 @@ static char *bsd_dktypenames[] = { "floppy", 0 }; -#define BSD_DKMAXTYPES (sizeof(bsd_dktypenames) / sizeof(bsd_dktypenames[0]) - 1) +#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1) #endif /* @@ -189,7 +173,6 @@ static char *bsd_dktypenames[] = { #define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */ #define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */ #define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */ -#define BSD_FS_MSDOS 8 /* MS-DOS file system */ #define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */ #define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */ #define BSD_FS_HPFS 11 /* OS/2 high-performance file system */ @@ -199,8 +182,15 @@ static char *bsd_dktypenames[] = { #define BSD_FS_ADOS 14 /* AmigaDOS fast file system */ #define BSD_FS_HFS 15 /* Macintosh HFS */ +/* this is annoying, but it's also the way it is :-( */ +#ifdef __alpha__ +#define BSD_FS_EXT2 8 /* MS-DOS file system */ +#else +#define BSD_FS_MSDOS 8 /* MS-DOS file system */ +#endif + #ifdef DKTYPENAMES -static struct systypes bsd_fstypes[] = { +static struct systypes xbsd_fstypes[] = { {BSD_FS_UNUSED, "unused"}, {BSD_FS_SWAP, "swap"}, {BSD_FS_V6, "Version 6"}, @@ -209,7 +199,11 @@ static struct systypes bsd_fstypes[] = { {BSD_FS_V71K, "4.1BSD"}, {BSD_FS_V8, "Eighth Edition"}, {BSD_FS_BSDFFS, "4.2BSD"}, +#ifdef __alpha__ + {BSD_FS_EXT2, "ext2"}, +#else {BSD_FS_MSDOS, "MS-DOS"}, +#endif {BSD_FS_BSDLFS, "4.4LFS"}, {BSD_FS_OTHER, "unknown"}, {BSD_FS_HPFS, "HPFS"}, @@ -219,7 +213,7 @@ static struct systypes bsd_fstypes[] = { {BSD_FS_HFS, "HFS"} }; -#define BSD_FSMAXTYPES (sizeof(bsd_fstypes) / sizeof(struct systypes)) +#define BSD_FSMAXTYPES (sizeof(xbsd_fstypes) / sizeof(struct systypes)) #endif /* diff --git a/disk-utils/fsck.minix.8 b/disk-utils/fsck.minix.8 index 024e1b7a3..f0d853751 100644 --- a/disk-utils/fsck.minix.8 +++ b/disk-utils/fsck.minix.8 @@ -1,7 +1,7 @@ .\" Copyright 1992, 1993, 1994 Rickard E. Faith (faith@cs.unc.edu) .\" May be freely distributed. .\" " for hilit19 -.TH FSCK 8 "10 January 1994" "Linux 0.99" "Linux Programmer's Manual" +.TH FSCK 8 "2 July 1996" "Util-Linux 2.6" "Linux Programmer's Manual" .SH NAME fsck.minix \- a file system consistency checker for Linux .SH SYNOPSIS @@ -22,10 +22,10 @@ searches for files). The device will usually have the following form: .nf .RS -/dev/hda[1-8] -/dev/hdb[1-8] -/dev/sda[1-8] -/dev/sdb[1-8] +/dev/hda[1-63] (IDE disk 1) +/dev/hdb[1-63] (IDE disk 2) +/dev/sda[1-15] (SCSI disk 1) +/dev/sdb[1-15] (SCSI disk 2) .RE .fi @@ -126,3 +126,9 @@ Added support for file system valid flag: Dr. Wettstein .br Check to prevent fsck of mounted filesystem added by Daniel Quinlan (quinlan@yggdrasil.com) +.br +Minix v2 fs support by Andreas Schwab +(schwab@issan.informatik.uni-dortmund.de), updated by Nicolai +Langfeldt (janl@math.uio.no) +.br +Portability patch by Russell King (rmk@ecs.soton.ac.uk). diff --git a/disk-utils/fsck.minix.c b/disk-utils/fsck.minix.c index 209f9ce71..0e8dc64e0 100644 --- a/disk-utils/fsck.minix.c +++ b/disk-utils/fsck.minix.c @@ -37,11 +37,31 @@ * added program_version variable and output of * program name and version number when program * is executed. - * + * + * 30.10.94 - added support for v2 filesystem + * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de) + * * 10.12.94 - added test to prevent checking of mounted fs adapted * from Theodore Ts'o's (tytso@athena.mit.edu) e2fsck * program. (Daniel Quinlan, quinlan@yggdrasil.com) * + * 01.07.96 - Fixed the v2 fs stuff to use the right #defines and such + * for modern libcs (janl@math.uio.no, Nicolai Langfeldt) + * + * 02.07.96 - Added C bit fiddling routines from rmk@ecs.soton.ac.uk + * (Russell King). He made them for ARM. It would seem + * that the ARM is powerfull enough to do this in C whereas + * i386 and m64k must use assembly to get it fast >:-) + * This should make minix fsck systemindependent. + * (janl@math.uio.no, Nicolai Langfeldt) + * + * 04.11.96 - Added minor fixes from Andreas Schwab to avoid compiler + * warnings. Added mc68k bitops from + * Joerg Dorchain <dorchain@mpi-sb.mpg.de>. + * + * 06.11.96 - Added v2 code submitted by Joerg Dorchain, but written by + * Andreas Schwab. + * * I've had no time to add comments - hopefully the function names * are comments enough. As with all file system checkers, this assumes * the file system is quiescent - don't use it on a mounted device @@ -62,6 +82,7 @@ */ #include <stdio.h> +#include <errno.h> #include <unistd.h> #include <string.h> #include <fcntl.h> @@ -73,9 +94,10 @@ #include <linux/fs.h> #include <linux/minix_fs.h> +#include "../version.h" -#ifndef __GNUC__ -#error "needs gcc for the bitop-__asm__'s" +#ifdef MINIX2_SUPER_MAGIC2 +#define HAVE_MINIX2 1 #endif #ifndef __linux__ @@ -86,13 +108,19 @@ #define UPPER(size,n) ((size+((n)-1))/(n)) #define INODE_SIZE (sizeof(struct minix_inode)) -#define INODE_BLOCKS UPPER(INODES,MINIX_INODES_PER_BLOCK) +#ifdef HAVE_MINIX2 +#define INODE_SIZE2 (sizeof(struct minix2_inode)) +#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \ + : MINIX_INODES_PER_BLOCK)) +#else +#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK)) +#endif #define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE) #define BITS_PER_BLOCK (BLOCK_SIZE<<3) static char * program_name = "fsck.minix"; -static char * program_version = "1.0 - 12/30/93"; +static char * program_version = "1.2 - 11/11/96"; static char * device_name = NULL; static int IN; static int repair=0, automatic=0, verbose=0, list=0, show=0, warn_mode=0, @@ -104,6 +132,9 @@ static int changed = 0; /* flags if the filesystem has been changed */ static int errors_uncorrected = 0; /* flag if some error was not corrected */ static int dirsize = 16; static int namelen = 14; +static int version2 = 0; +static struct termios termios; +static int termios_set = 0; /* File-name data */ #define MAX_DEPTH 50 @@ -112,10 +143,15 @@ static char name_list[MAX_DEPTH][NAME_MAX+1]; static char * inode_buffer = NULL; #define Inode (((struct minix_inode *) inode_buffer)-1) +#define Inode2 (((struct minix2_inode *) inode_buffer)-1) static char super_block_buffer[BLOCK_SIZE]; #define Super (*(struct minix_super_block *)super_block_buffer) #define INODES ((unsigned long)Super.s_ninodes) -#define ZONES ((unsigned long)Super.s_nzones) +#ifdef HAVE_MINIX2 +#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones)) +#else +#define ZONES ((unsigned long)(Super.s_nzones)) +#endif #define IMAPS ((unsigned long)Super.s_imap_blocks) #define ZMAPS ((unsigned long)Super.s_zmap_blocks) #define FIRSTZONE ((unsigned long)Super.s_firstdatazone) @@ -131,20 +167,9 @@ static unsigned char * inode_count = NULL; static unsigned char * zone_count = NULL; void recursive_check(unsigned int ino); +void recursive_check2(unsigned int ino); -#define bitop(name,op) \ -static inline int name(char * addr,unsigned int nr) \ -{ \ -int __res; \ -__asm__ __volatile__("bt" op "l %1,%2; adcl $0,%0" \ -:"=g" (__res) \ -:"r" (nr),"m" (*(addr)),"0" (0)); \ -return __res; \ -} - -bitop(bit,"") -bitop(setbit,"s") -bitop(clrbit,"r") +#include "bitops.h" #define inode_in_use(x) (bit(inode_map,(x))) #define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1)) @@ -155,14 +180,12 @@ bitop(clrbit,"r") #define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1),changed=1) #define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1),changed=1) -/* - * Volatile to let gcc know that this doesn't return. When trying - * to compile this under minix, volatile gives a warning, as - * exit() isn't defined as volatile under minix. - */ -volatile void fatal_error(const char * fmt_string, int status) +void fatal_error(const char *, int) __attribute__ ((noreturn)); +void fatal_error(const char * fmt_string, int status) { fprintf(stderr,fmt_string,program_name,device_name); + if (termios_set) + tcsetattr(0, TCSANOW, &termios); exit(status); } @@ -179,6 +202,8 @@ void print_current_name(void) while (i<name_depth) printf("/%.*s",namelen,name_list[i++]); + if (i == 0) + printf ("/"); } int ask(const char * string,int def) @@ -292,6 +317,26 @@ int check_zone_nr(unsigned short * nr, int * corrected) return 0; } + +int check_zone_nr2 (unsigned int *nr, int *corrected) +{ + if (!*nr) + return 0; + if (*nr < FIRSTZONE) + printf ("Zone nr < FIRSTZONE in file `"); + else if (*nr >= ZONES) + printf ("Zone nr >= ZONES in file `"); + else + return *nr; + print_current_name (); + printf ("'."); + if (ask ("Remove block", 1)) { + *nr = 0; + *corrected = 1; + } + return 0; +} + /* * read-block reads block nr into the buffer at addr. */ @@ -378,6 +423,65 @@ int map_block(struct minix_inode * inode, unsigned int blknr) return result; } +#ifdef HAVE_MINIX2 +int map_block2 (struct minix2_inode *inode, unsigned int blknr) +{ + unsigned int ind[BLOCK_SIZE >> 2]; + unsigned int dind[BLOCK_SIZE >> 2]; + unsigned int tind[BLOCK_SIZE >> 2]; + int blk_chg, block, result; + + if (blknr < 7) + return check_zone_nr2 (inode->i_zone + blknr, &changed); + blknr -= 7; + if (blknr < 256) { + block = check_zone_nr2 (inode->i_zone + 7, &changed); + read_block (block, (char *) ind); + blk_chg = 0; + result = check_zone_nr2 (blknr + ind, &blk_chg); + if (blk_chg) + write_block (block, (char *) ind); + return result; + } + blknr -= 256; + if (blknr >= 256 * 256) { + block = check_zone_nr2 (inode->i_zone + 8, &changed); + read_block (block, (char *) dind); + blk_chg = 0; + result = check_zone_nr2 (dind + blknr / 256, &blk_chg); + if (blk_chg) + write_block (block, (char *) dind); + block = result; + read_block (block, (char *) ind); + blk_chg = 0; + result = check_zone_nr2 (ind + blknr % 256, &blk_chg); + if (blk_chg) + write_block (block, (char *) ind); + return result; + } + blknr -= 256 * 256; + block = check_zone_nr2 (inode->i_zone + 9, &changed); + read_block (block, (char *) tind); + blk_chg = 0; + result = check_zone_nr2 (tind + blknr / (256 * 256), &blk_chg); + if (blk_chg) + write_block (block, (char *) tind); + block = result; + read_block (block, (char *) dind); + blk_chg = 0; + result = check_zone_nr2 (dind + (blknr / 256) % 256, &blk_chg); + if (blk_chg) + write_block (block, (char *) dind); + block = result; + read_block (block, (char *) ind); + blk_chg = 0; + result = check_zone_nr2 (ind + blknr % 256, &blk_chg); + if (blk_chg) + write_block (block, (char *) ind); + return result; +} +#endif + void write_super_block(void) { /* @@ -411,10 +515,31 @@ void write_tables(void) die("Unable to write inodes"); } -void read_tables(void) +void get_dirsize (void) +{ + int block; + char blk[BLOCK_SIZE]; + int size; + +#if HAVE_MINIX2 + if (version2) + block = Inode2[ROOT_INO].i_zone[0]; + else +#endif + block = Inode[ROOT_INO].i_zone[0]; + read_block (block, blk); + for (size = 16; size < BLOCK_SIZE; size <<= 1) { + if (strcmp (blk + size + 2, "..") == 0) { + dirsize = size; + namelen = size - 2; + return; + } + } + /* use defaults */ +} + +void read_superblock(void) { - memset(inode_map,0,sizeof(inode_map)); - memset(zone_map,0,sizeof(zone_map)); if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET)) die("seek failed"); if (BLOCK_SIZE != read(IN, super_block_buffer, BLOCK_SIZE)) @@ -422,9 +547,21 @@ void read_tables(void) if (MAGIC == MINIX_SUPER_MAGIC) { namelen = 14; dirsize = 16; + version2 = 0; } else if (MAGIC == MINIX_SUPER_MAGIC2) { namelen = 30; dirsize = 32; + version2 = 0; +#ifdef HAVE_MINIX2 + } else if (MAGIC == MINIX2_SUPER_MAGIC) { + namelen = 14; + dirsize = 16; + version2 = 1; + } else if (MAGIC == MINIX2_SUPER_MAGIC2) { + namelen = 30; + dirsize = 32; + version2 = 1; +#endif } else die("bad magic number in super-block"); if (ZONESIZE != 0 || BLOCK_SIZE != 1024) @@ -433,6 +570,12 @@ void read_tables(void) die("bad s_imap_blocks field in super-block"); if (!ZMAPS || ZMAPS > MINIX_Z_MAP_SLOTS) die("bad s_zmap_blocks field in super-block"); +} + +void read_tables(void) +{ + memset(inode_map,0,sizeof(inode_map)); + memset(zone_map,0,sizeof(zone_map)); inode_buffer = malloc(INODE_BUFFER_SIZE); if (!inode_buffer) die("Unable to allocate buffer for inodes"); @@ -452,12 +595,13 @@ void read_tables(void) printf("Warning: Firstzone != Norm_firstzone\n"); errors_uncorrected = 1; } + get_dirsize (); if (show) { - printf("%d inodes\n",INODES); - printf("%d blocks\n",ZONES); - printf("Firstdatazone=%d (%d)\n",FIRSTZONE,NORM_FIRSTZONE); + printf("%ld inodes\n",INODES); + printf("%ld blocks\n",ZONES); + printf("Firstdatazone=%ld (%ld)\n",FIRSTZONE,NORM_FIRSTZONE); printf("Zonesize=%d\n",BLOCK_SIZE<<ZONESIZE); - printf("Maxsize=%d\n",MAXSIZE); + printf("Maxsize=%ld\n",MAXSIZE); printf("Filesystem state=%d\n", Super.s_state); printf("namelen=%d\n\n",namelen); } @@ -512,6 +656,55 @@ struct minix_inode * get_inode(unsigned int nr) return inode; } +#ifdef HAVE_MINIX2 +struct minix2_inode * +get_inode2 (unsigned int nr) +{ + struct minix2_inode *inode; + + if (!nr || nr >= INODES) + return NULL; + total++; + inode = Inode2 + nr; + if (!inode_count[nr]) { + if (!inode_in_use (nr)) { + printf ("Inode %d marked not used, but used for file '", nr); + print_current_name (); + printf ("'\n"); + if (repair) { + if (ask ("Mark in use", 1)) + mark_inode (nr); + else + errors_uncorrected = 1; + } + } + if (S_ISDIR (inode->i_mode)) + directory++; + else if (S_ISREG (inode->i_mode)) + regular++; + else if (S_ISCHR (inode->i_mode)) + chardev++; + else if (S_ISBLK (inode->i_mode)) + blockdev++; + else if (S_ISLNK (inode->i_mode)) + symlinks++; + else if (S_ISSOCK (inode->i_mode)); + else if (S_ISFIFO (inode->i_mode)); + else { + print_current_name (); + printf (" has mode %05o\n", inode->i_mode); + } + } else + links++; + if (!++inode_count[nr]) { + printf ("Warning: inode count too big.\n"); + inode_count[nr]--; + errors_uncorrected = 1; + } + return inode; +} +#endif + void check_root(void) { struct minix_inode * inode = Inode + ROOT_INO; @@ -520,6 +713,16 @@ void check_root(void) die("root inode isn't a directory"); } +#ifdef HAVE_MINIX2 +void check_root2 (void) +{ + struct minix2_inode *inode = Inode2 + ROOT_INO; + + if (!inode || !S_ISDIR (inode->i_mode)) + die ("root inode isn't a directory"); +} +#endif + static int add_zone(unsigned short * znr, int * corrected) { int result; @@ -553,6 +756,40 @@ static int add_zone(unsigned short * znr, int * corrected) return block; } + +static int add_zone2 (unsigned int *znr, int *corrected) +{ + int result; + int block; + + result = 0; + block = check_zone_nr2 (znr, corrected); + if (!block) + return 0; + if (zone_count[block]) { + printf ("Block has been used before. Now in file `"); + print_current_name (); + printf ("'."); + if (ask ("Clear", 1)) { + *znr = 0; + block = 0; + *corrected = 1; + } + } + if (!block) + return 0; + if (!zone_in_use (block)) { + printf ("Block %d in file `", block); + print_current_name (); + printf ("' is marked not in use."); + if (ask ("Correct", 1)) + mark_zone (block); + } + if (!++zone_count[block]) + zone_count[block]--; + return block; +} + static void add_zone_ind(unsigned short * znr, int * corrected) { static char blk[BLOCK_SIZE]; @@ -569,6 +806,22 @@ static void add_zone_ind(unsigned short * znr, int * corrected) write_block(block, blk); } +static void add_zone_ind2 (unsigned int *znr, int *corrected) +{ + static char blk[BLOCK_SIZE]; + int i, chg_blk = 0; + int block; + + block = add_zone2 (znr, corrected); + if (!block) + return; + read_block (block, blk); + for (i = 0; i < BLOCK_SIZE >> 2; i++) + add_zone2 (i + (unsigned int *) blk, &chg_blk); + if (chg_blk) + write_block (block, blk); +} + static void add_zone_dind(unsigned short * znr, int * corrected) { static char blk[BLOCK_SIZE]; @@ -585,6 +838,40 @@ static void add_zone_dind(unsigned short * znr, int * corrected) write_block(block, blk); } +static void +add_zone_dind2 (unsigned int *znr, int *corrected) +{ + static char blk[BLOCK_SIZE]; + int i, blk_chg = 0; + int block; + + block = add_zone2 (znr, corrected); + if (!block) + return; + read_block (block, blk); + for (i = 0; i < BLOCK_SIZE >> 2; i++) + add_zone_ind2 (i + (unsigned int *) blk, &blk_chg); + if (blk_chg) + write_block (block, blk); +} + +static void +add_zone_tind2 (unsigned int *znr, int *corrected) +{ + static char blk[BLOCK_SIZE]; + int i, blk_chg = 0; + int block; + + block = add_zone2 (znr, corrected); + if (!block) + return; + read_block (block, blk); + for (i = 0; i < BLOCK_SIZE >> 2; i++) + add_zone_dind2 (i + (unsigned int *) blk, &blk_chg); + if (blk_chg) + write_block (block, blk); +} + void check_zones(unsigned int i) { struct minix_inode * inode; @@ -603,6 +890,28 @@ void check_zones(unsigned int i) add_zone_dind(8 + inode->i_zone, &changed); } +#ifdef HAVE_MINIX2 +void +check_zones2 (unsigned int i) +{ + struct minix2_inode *inode; + + if (!i || i >= INODES) + return; + if (inode_count[i] > 1) /* have we counted this file already? */ + return; + inode = Inode2 + i; + if (!S_ISDIR (inode->i_mode) && !S_ISREG (inode->i_mode) + && !S_ISLNK (inode->i_mode)) + return; + for (i = 0; i < 7; i++) + add_zone2 (i + inode->i_zone, &changed); + add_zone_ind2 (7 + inode->i_zone, &changed); + add_zone_dind2 (8 + inode->i_zone, &changed); + add_zone_tind2 (9 + inode->i_zone, &changed); +} +#endif + void check_file(struct minix_inode * dir, unsigned int offset) { static char blk[BLOCK_SIZE]; @@ -625,7 +934,11 @@ void check_file(struct minix_inode * dir, unsigned int offset) } ino = 0; } + if (name_depth < MAX_DEPTH) + strncpy (name_list[name_depth], name, namelen); + name_depth++; inode = get_inode(ino); + name_depth--; if (!offset) if (!inode || strcmp(".",name)) { print_current_name(); @@ -659,6 +972,71 @@ void check_file(struct minix_inode * dir, unsigned int offset) return; } +#ifdef HAVE_MINIX2 +void +check_file2 (struct minix2_inode *dir, unsigned int offset) +{ + static char blk[BLOCK_SIZE]; + struct minix2_inode *inode; + int ino; + char *name; + int block; + + block = map_block2 (dir, offset / BLOCK_SIZE); + read_block (block, blk); + name = blk + (offset % BLOCK_SIZE) + 2; + ino = *(unsigned short *) (name - 2); + if (ino >= INODES) { + print_current_name (); + printf (" contains a bad inode number for file '"); + printf ("%.*s'.", namelen, name); + if (ask (" Remove", 1)) { + *(unsigned short *) (name - 2) = 0; + write_block (block, blk); + } + ino = 0; + } + if (name_depth < MAX_DEPTH) + strncpy (name_list[name_depth], name, namelen); + name_depth++; + inode = get_inode2 (ino); + name_depth--; + if (!offset) { + if (!inode || strcmp (".", name)) { + print_current_name (); + printf (": bad directory: '.' isn't first\n"); + errors_uncorrected = 1; + } else + return; + } + if (offset == dirsize) { + if (!inode || strcmp ("..", name)) { + print_current_name (); + printf (": bad directory: '..' isn't second\n"); + errors_uncorrected = 1; + } else + return; + } + if (!inode) + return; + name_depth++; + if (list) { + if (verbose) + printf ("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks); + print_current_name (); + if (S_ISDIR (inode->i_mode)) + printf (":\n"); + else + printf ("\n"); + } + check_zones2 (ino); + if (inode && S_ISDIR (inode->i_mode)) + recursive_check2 (ino); + name_depth--; + return; +} +#endif + void recursive_check(unsigned int ino) { struct minix_inode * dir; @@ -667,7 +1045,7 @@ void recursive_check(unsigned int ino) dir = Inode + ino; if (!S_ISDIR(dir->i_mode)) die("internal error"); - if (dir->i_size < 32) { + if (dir->i_size < 2 * dirsize) { print_current_name(); printf(": bad directory: size<32"); errors_uncorrected = 1; @@ -676,6 +1054,26 @@ void recursive_check(unsigned int ino) check_file(dir,offset); } +#ifdef HAVE_MINIX2 +void +recursive_check2 (unsigned int ino) +{ + struct minix2_inode *dir; + unsigned int offset; + + dir = Inode2 + ino; + if (!S_ISDIR (dir->i_mode)) + die ("internal error"); + if (dir->i_size < 2 * dirsize) { + print_current_name (); + printf (": bad directory: size < 32"); + errors_uncorrected = 1; + } + for (offset = 0; offset < dir->i_size; offset += dirsize) + check_file2 (dir, offset); +} +#endif + int bad_zone(int i) { char buffer[1024]; @@ -736,6 +1134,59 @@ void check_counts(void) } } +#ifdef HAVE_MINIX2 +void +check_counts2 (void) +{ + int i; + + for (i = 1; i < INODES; i++) { + if (!inode_in_use (i) && Inode2[i].i_mode && warn_mode) { + printf ("Inode %d mode not cleared.", i); + if (ask ("Clear", 1)) { + Inode2[i].i_mode = 0; + changed = 1; + } + } + if (!inode_count[i]) { + if (!inode_in_use (i)) + continue; + printf ("Inode %d not used, marked used in the bitmap.", i); + if (ask ("Clear", 1)) + unmark_inode (i); + continue; + } + if (!inode_in_use (i)) { + printf ("Inode %d used, marked unused in the bitmap.", i); + if (ask ("Set", 1)) + mark_inode (i); + } + if (Inode2[i].i_nlinks != inode_count[i]) { + printf ("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.", + i, Inode2[i].i_mode, Inode2[i].i_nlinks, inode_count[i]); + if (ask ("Set i_nlinks to count", 1)) { + Inode2[i].i_nlinks = inode_count[i]; + changed = 1; + } + } + } + for (i = FIRSTZONE; i < ZONES; i++) { + if (zone_in_use (i) == zone_count[i]) + continue; + if (!zone_count[i]) { + if (bad_zone (i)) + continue; + printf ("Zone %d: marked in use, no file uses it.", i); + if (ask ("Unmark", 1)) + unmark_zone (i); + continue; + } + printf ("Zone %d: %sin use, counted=%d\n", + i, zone_in_use (i) ? "" : "not ", zone_count[i]); + } +} +#endif + void check(void) { memset(inode_count,0,INODES*sizeof(*inode_count)); @@ -745,9 +1196,21 @@ void check(void) check_counts(); } +#ifdef HAVE_MINIX2 +void +check2 (void) +{ + memset (inode_count, 0, INODES * sizeof (*inode_count)); + memset (zone_count, 0, ZONES * sizeof (*zone_count)); + check_zones2 (ROOT_INO); + recursive_check2 (ROOT_INO); + check_counts2 (); +} +#endif + int main(int argc, char ** argv) { - struct termios termios,tmp; + struct termios tmp; int count; int retcode = 0; @@ -755,6 +1218,10 @@ int main(int argc, char ** argv) program_name = *argv; if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) die("bad inode size"); +#ifdef HAVE_MINIX2 + if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) + die("bad v2 inode size"); +#endif while (argc-- > 1) { argv++; if (argv[0][0] != '-') @@ -780,17 +1247,13 @@ int main(int argc, char ** argv) if (repair && !automatic) { if (!isatty(0) || !isatty(1)) die("need terminal for interactive repairs"); - tcgetattr(0,&termios); - tmp = termios; - tmp.c_lflag &= ~(ICANON|ECHO); - tcsetattr(0,TCSANOW,&tmp); } IN = open(device_name,repair?O_RDWR:O_RDONLY); if (IN < 0) die("unable to open '%s'"); for (count=0 ; count<3 ; count++) sync(); - read_tables(); + read_superblock(); /* * Determine whether or not we should continue with the checking. @@ -798,14 +1261,13 @@ int main(int argc, char ** argv) * flags and whether or not the -f switch was specified on the * command line. */ - printf("%s, %s\n", program_name, program_version); + printf("%s, %s / %s\n", program_name, program_version, + util_linux_version); if ( !(Super.s_state & MINIX_ERROR_FS) && (Super.s_state & MINIX_VALID_FS) && !force ) { if (repair) printf("%s is clean, no check.\n", device_name); - if (repair && !automatic) - tcsetattr(0,TCSANOW,&termios); return retcode; } else if (force) @@ -814,20 +1276,38 @@ int main(int argc, char ** argv) printf("Filesystem on %s is dirty, needs checking.\n",\ device_name); - check_root(); - check(); + read_tables(); + + if (repair && !automatic) { + tcgetattr(0,&termios); + tmp = termios; + tmp.c_lflag &= ~(ICANON|ECHO); + tcsetattr(0,TCSANOW,&tmp); + termios_set = 1; + } + +#if HAVE_MINIX2 + if (version2) { + check_root2 (); + check2 (); + } else +#endif + { + check_root(); + check(); + } if (verbose) { int i, free; for (i=1,free=0 ; i < INODES ; i++) if (!inode_in_use(i)) free++; - printf("\n%6d inodes used (%d%%)\n",(INODES-free-1), + printf("\n%6ld inodes used (%ld%%)\n",(INODES-free-1), 100*(INODES-free-1)/(INODES-1)); for (i=FIRSTZONE,free=0 ; i < ZONES ; i++) if (!zone_in_use(i)) free++; - printf("%6d zones used (%d%%)\n",(ZONES-free), + printf("%6ld zones used (%ld%%)\n",(ZONES-free), 100*(ZONES-free)/ZONES); printf("\n%6d regular files\n" "%6d directories\n" diff --git a/disk-utils/llseek.c b/disk-utils/llseek.c index 3e59ec953..dcbfb2a45 100644 --- a/disk-utils/llseek.c +++ b/disk-utils/llseek.c @@ -11,26 +11,39 @@ #include <errno.h> #include <unistd.h> -#include <linux/unistd.h> + #ifndef FOR_UTIL_LINUX + #include "et/com_err.h" #include "ext2fs/io.h" -#endif -#ifdef FOR_UTIL_LINUX +#else /* FOR_UTIL_LINUX */ + #if defined(__GNUC__) || defined(HAS_LONG_LONG) -typedef long long ext2_loff_t; +typedef long long ext2_loff_t; #else -typedef long ext2_loff_t; +typedef long ext2_loff_t; #endif -extern ext2_loff_t ext2_llseek(unsigned int fd, - ext2_loff_t offset, - unsigned int origin); -#endif +ext2_loff_t ext2_llseek (unsigned int, ext2_loff_t, unsigned int); + +#endif /* FOR_UTIL_LINUX */ #ifdef __linux__ +#ifdef HAVE_LLSEEK +#include <syscall.h> + +#else /* HAVE_LLSEEK */ + +#ifdef __alpha__ + +#define my_llseek lseek + +#elif __i386__ + +#include <linux/unistd.h> + #ifndef __NR__llseek #define __NR__llseek 140 #endif @@ -42,54 +55,66 @@ static _syscall5(int,_llseek,unsigned int,fd,unsigned long,offset_high, unsigned long, offset_low,ext2_loff_t *,result, unsigned int, origin) +static ext2_loff_t my_llseek (unsigned int fd, ext2_loff_t offset, + unsigned int origin) +{ + ext2_loff_t result; + int retval; + + retval = _llseek (fd, ((unsigned long long) offset) >> 32, + ((unsigned long long) offset) & 0xffffffff, + &result, origin); + return (retval == -1 ? (ext2_loff_t) retval : result); +} + +#else + +#error "llseek() is not available" + +#endif /* __alpha__ */ + +#endif /* HAVE_LLSEEK */ + ext2_loff_t ext2_llseek (unsigned int fd, ext2_loff_t offset, unsigned int origin) { - unsigned long offset_high; - unsigned long offset_low; ext2_loff_t result; - int retval; static int do_compat = 0; + if ((sizeof(off_t) >= sizeof(ext2_loff_t)) || + (offset < ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))) + return lseek(fd, (off_t) offset, origin); + if (do_compat) { - compat_lseek: - if ((sizeof(off_t) < sizeof(ext2_loff_t)) && - (offset >= ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))) { - errno = -EINVAL; - return -1; - } - return lseek (fd, (off_t) offset, origin); + errno = EINVAL; + return -1; } - offset_high = ((unsigned long long) offset) >> 32; - offset_low = ((unsigned long long) offset) & 0xffffffff; - retval = _llseek (fd, offset_high, offset_low, &result, origin); - if (retval == -1 && errno == ENOSYS) { + result = my_llseek (fd, offset, origin); + if (result == -1 && errno == ENOSYS) { /* * Just in case this code runs on top of an old kernel * which does not support the llseek system call */ do_compat++; - goto compat_lseek; + errno = EINVAL; } - if (retval == -1) - result = -1; return result; } -#else +#else /* !linux */ ext2_loff_t ext2_llseek (unsigned int fd, ext2_loff_t offset, unsigned int origin) { if ((sizeof(off_t) < sizeof(ext2_loff_t)) && (offset >= ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))) { - errno = -EINVAL; + errno = EINVAL; return -1; } return lseek (fd, (off_t) offset, origin); } -#endif +#endif /* linux */ diff --git a/disk-utils/mkfs.c b/disk-utils/mkfs.c index 78a3a0c2f..8d4671915 100644 --- a/disk-utils/mkfs.c +++ b/disk-utils/mkfs.c @@ -7,6 +7,9 @@ * Authors: David Engel, <david@ods.com> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Ron Sommeling, <sommel@sci.kun.nl> + * + * Mon Jul 1 18:52:58 1996: janl@math.uio.no (Nicolai Langfeldt): + * Incorporated fix by Jonathan Kamens <jik@annex-1-slip-jik.cam.ov.com> */ @@ -17,10 +20,10 @@ #include <limits.h> -#define VERSION "1.9" +#define VERSION "1.10" #ifndef DEFAULT_FSTYPE -# define DEFAULT_FSTYPE "minix" +# define DEFAULT_FSTYPE "ext2" #endif #define SEARCH_PATH "PATH=/sbin:/sbin/fs.d:/sbin/fs:/etc/fs:/etc" @@ -44,6 +47,7 @@ int main(int argc, char *argv[]) fstype = optarg; break; default: + optind--; more = 1; break; /* start of specific arguments */ } diff --git a/disk-utils/mkfs.minix.8 b/disk-utils/mkfs.minix.8 index 3c59bb073..8f9e70242 100644 --- a/disk-utils/mkfs.minix.8 +++ b/disk-utils/mkfs.minix.8 @@ -1,21 +1,19 @@ .\" Copyright 1992, 1993, 1994 Rickard E. Faith (faith@cs.unc.edu) .\" May be freely distributed. .\" " for emacs hilit19 mode -.TH MKFS 8 "10 January 1994" "Linux 0.99" "Linux Programmer's Manual" +.TH MKFS 8 "2 July 1996" "Util-linux 2.6" "Linux System Administrator's Manual" .SH NAME mkfs \- make a Linux MINIX filesystem .SH SYNOPSIS -.BR "mkfs [ \-c ] [ \-n" +.BR "mkfs [ \-c | \-l filename ] [ \-n" namelength .B ] [ \-i inodecount +.B ] [ \-v ] +device +.B [ +size-in-blocks .B ] -device size-in-blocks -.br -.B "mkfs [ \-l" -filename -.B ] -device size-in-blocks .SH DESCRIPTION .B mkfs creates a Linux MINIX file-system on a device (usually a disk partition). @@ -26,10 +24,10 @@ is usually of the following form: .nf .RS -/dev/hda[1-8] -/dev/hdb[1-8] -/dev/sda[1-8] -/dev/sdb[1-8] +/dev/hda[1-8] (IDE disk 1) +/dev/hdb[1-8] (IDE disk 2) +/dev/sda[1-8] (SCSI disk 1) +/dev/sdb[1-8] (SCSI disk 2) .RE .fi @@ -38,8 +36,11 @@ The parameter is the desired size of the file system, in blocks. This information can be determined from the .BR fdisk (8) -program. Only block counts strictly greater than 10 and strictly less than -65536 are allowed. +or +.BR cfdisk (8) +program. If omitted it will be determined automaticaly. Only block +counts strictly greater than 10 and strictly less than 65536 are +allowed. .SH OPTIONS .TP .B \-c @@ -62,6 +63,9 @@ Read the bad blocks list from .IR filename . The file has one bad block number per line. The count of bad blocks read is printed. +.TP +.B \-v +Make a Minix version 2 filesystem. .SH "EXIT CODES" The exit code returned by .B mkfs.minix @@ -77,8 +81,8 @@ Usage or syntax error .BR mkefs (8), .BR efsck (8), .BR reboot (8) -.SH AUTHOR -Linus Torvalds (torvalds@cs.helsinki.fi) +.SH AUTHORS +Stared by Linus Torvalds (torvalds@cs.helsinki.fi). .br Error code values by Rik Faith (faith@cs.unc.edu) .br @@ -89,3 +93,9 @@ Support for the file system valid flag by Dr. Wettstein .br Check to prevent mkfs of mounted filesystem and boot sector clearing by Daniel Quinlan (quinlan@yggdrasil.com) +.br +Minix v2 support by Andreas Schwab +(schwab@issan.informatik.uni-dortmund.de), updated by Nicolai +Langfeldt (janl@math.uio.no) +.br +Portability patch by Russell King.
\ No newline at end of file diff --git a/disk-utils/mkfs.minix.c b/disk-utils/mkfs.minix.c index 87c7c1270..403a278c9 100644 --- a/disk-utils/mkfs.minix.c +++ b/disk-utils/mkfs.minix.c @@ -31,6 +31,9 @@ * * 03.01.94 - Added support for file system valid flag. * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu) + * + * 30.10.94 - added support for v2 filesystem + * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de) * * 09.11.94 - Added test to prevent overwrite of mounted fs adapted * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs @@ -40,13 +43,16 @@ * the filesystem is not misidentified as a MS-DOS FAT filesystem. * (Daniel Quinlan, quinlan@yggdrasil.com) * - * Usage: mkfs [-c] [-nXX] [-iXX] device size-in-blocks - * mkfs [-l filename ] device size-in-blocks + * 02.07.96 - Added small patch from Russell King to make the program a + * good deal more portable (janl@math.uio.no) + * + * Usage: mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks] * * -c for readablility checking (SLOW!) * -l for getting a list of bad blocks from a file. * -n for namelength (currently the kernel only uses 14 or 30) * -i for number of inodes + * -v for v2 filesystem * * The device may be a block device or a image of one, but this isn't * enforced (but it's not much fun on a character device :-). @@ -62,11 +68,16 @@ #include <stdlib.h> #include <termios.h> #include <sys/stat.h> +#include <sys/ioctl.h> #include <mntent.h> #include <linux/fs.h> #include <linux/minix_fs.h> +#ifdef MINIX2_SUPER_MAGIC2 +#define HAVE_MINIX2 1 +#endif + #ifndef __GNUC__ #error "needs gcc for the bitop-__asm__'s" #endif @@ -83,7 +94,13 @@ #define UPPER(size,n) ((size+((n)-1))/(n)) #define INODE_SIZE (sizeof(struct minix_inode)) -#define INODE_BLOCKS UPPER(INODES,MINIX_INODES_PER_BLOCK) +#ifdef HAVE_MINIX2 +#define INODE_SIZE2 (sizeof(struct minix2_inode)) +#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \ + : MINIX_INODES_PER_BLOCK)) +#else +#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK)) +#endif #define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE) #define BITS_PER_BLOCK (BLOCK_SIZE<<3) @@ -96,18 +113,26 @@ static int check = 0; static int badblocks = 0; static int namelen = 30; /* default (changed to 30, per Linus's suggestion, Sun Nov 21 08:05:07 1993) */ -static int dirsize = 16; -static int magic = MINIX_SUPER_MAGIC; +static int dirsize = 32; +static int magic = MINIX_SUPER_MAGIC2; +static int version2 = 0; static char root_block[BLOCK_SIZE] = "\0"; static char * inode_buffer = NULL; #define Inode (((struct minix_inode *) inode_buffer)-1) +#ifdef HAVE_MINIX2 +#define Inode2 (((struct minix2_inode *) inode_buffer)-1) +#endif static char super_block_buffer[BLOCK_SIZE]; static char boot_block_buffer[512]; #define Super (*(struct minix_super_block *)super_block_buffer) #define INODES ((unsigned long)Super.s_ninodes) -#define ZONES ((unsigned long)Super.s_nzones) +#ifdef HAVE_MINIX2 +#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones)) +#else +#define ZONES ((unsigned long)(Super.s_nzones)) +#endif #define IMAPS ((unsigned long)Super.s_imap_blocks) #define ZMAPS ((unsigned long)Super.s_zmap_blocks) #define FIRSTZONE ((unsigned long)Super.s_firstdatazone) @@ -123,19 +148,7 @@ static unsigned short good_blocks_table[MAX_GOOD_BLOCKS]; static int used_good_blocks = 0; static unsigned long req_nr_inodes = 0; -#define bitop(name,op) \ -static inline int name(char * addr,unsigned int nr) \ -{ \ -int __res; \ -__asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \ -:"=g" (__res) \ -:"r" (nr),"m" (*(addr)),"0" (0)); \ -return __res; \ -} - -bitop(bit,"") -bitop(setbit,"s") -bitop(clrbit,"r") +#include "bitops.h" #define inode_in_use(x) (bit(inode_map,(x))) #define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1)) @@ -157,7 +170,7 @@ volatile void fatal_error(const char * fmt_string,int status) exit(status); } -#define usage() fatal_error("Usage: %s [-c | -l filename] [-nXX] [-iXX] /dev/name blocks\n",16) +#define usage() fatal_error("Usage: %s [-c | -l filename] [-nXX] [-iXX] /dev/name [blocks]\n",16) #define die(str) fatal_error("%s: " str "\n",8) /* @@ -182,6 +195,57 @@ static void check_mount(void) die("%s is mounted; will not make a filesystem here!"); } +static long valid_offset (int fd, int offset) +{ + char ch; + + if (lseek (fd, offset, 0) < 0) + return 0; + if (read (fd, &ch, 1) < 1) + return 0; + return 1; +} + +static int count_blocks (int fd) +{ + int high, low; + + low = 0; + for (high = 1; valid_offset (fd, high); high *= 2) + low = high; + while (low < high - 1) + { + const int mid = (low + high) / 2; + + if (valid_offset (fd, mid)) + low = mid; + else + high = mid; + } + valid_offset (fd, 0); + return (low + 1); +} + +static int get_size(const char *file) +{ + int fd; + int size; + + fd = open(file, O_RDWR); + if (fd < 0) { + perror(file); + exit(1); + } + if (ioctl(fd, BLKGETSIZE, &size) >= 0) { + close(fd); + return (size * 512); + } + + size = count_blocks(fd); + close(fd); + return size; +} + void write_tables(void) { /* Mark the super block valid. */ @@ -300,6 +364,58 @@ end_bad: write_block(dind, (char *) dind_block); } +#ifdef HAVE_MINIX2 +void +make_bad_inode2 (void) +{ + struct minix2_inode *inode = &Inode2[MINIX_BAD_INO]; + int i, j, zone; + int ind = 0, dind = 0; + unsigned long ind_block[BLOCK_SIZE >> 2]; + unsigned long dind_block[BLOCK_SIZE >> 2]; + + if (!badblocks) + return; + mark_inode (MINIX_BAD_INO); + inode->i_nlinks = 1; + inode->i_atime = inode->i_mtime = inode->i_ctime = time (NULL); + inode->i_mode = S_IFREG + 0000; + inode->i_size = badblocks * BLOCK_SIZE; + zone = next (0); + for (i = 0; i < 7; i++) { + inode->i_zone[i] = zone; + if (!NEXT_BAD) + goto end_bad; + } + inode->i_zone[7] = ind = get_free_block (); + memset (ind_block, 0, BLOCK_SIZE); + for (i = 0; i < 256; i++) { + ind_block[i] = zone; + if (!NEXT_BAD) + goto end_bad; + } + inode->i_zone[8] = dind = get_free_block (); + memset (dind_block, 0, BLOCK_SIZE); + for (i = 0; i < 256; i++) { + write_block (ind, (char *) ind_block); + dind_block[i] = ind = get_free_block (); + memset (ind_block, 0, BLOCK_SIZE); + for (j = 0; j < 256; j++) { + ind_block[j] = zone; + if (!NEXT_BAD) + goto end_bad; + } + } + /* Could make triple indirect block here */ + die ("too many bad blocks"); + end_bad: + if (ind) + write_block (ind, (char *) ind_block); + if (dind) + write_block (dind, (char *) dind_block); +} +#endif + void make_root_inode(void) { struct minix_inode * inode = &Inode[MINIX_ROOT_INO]; @@ -319,9 +435,32 @@ void make_root_inode(void) write_block(inode->i_zone[0],root_block); } +#ifdef HAVE_MINIX2 +void +make_root_inode2 (void) +{ + struct minix2_inode *inode = &Inode2[MINIX_ROOT_INO]; + + mark_inode (MINIX_ROOT_INO); + inode->i_zone[0] = get_free_block (); + inode->i_nlinks = 2; + inode->i_atime = inode->i_mtime = inode->i_ctime = time (NULL); + if (badblocks) + inode->i_size = 3 * dirsize; + else { + root_block[2 * dirsize] = '\0'; + root_block[2 * dirsize + 1] = '\0'; + inode->i_size = 2 * dirsize; + } + inode->i_mode = S_IFDIR + 0755; + write_block (inode->i_zone[0], root_block); +} +#endif + void setup_tables(void) { int i; + unsigned long inodes; memset(inode_map,0xff,sizeof(inode_map)); memset(zone_map,0xff,sizeof(zone_map)); @@ -329,13 +468,16 @@ void setup_tables(void) memset(boot_block_buffer,0,512); MAGIC = magic; ZONESIZE = 0; - MAXSIZE = (7+512+512*512)*1024; + MAXSIZE = version2 ? 0x7fffffff : (7+512+512*512)*1024; ZONES = BLOCKS; /* some magic nrs: 1 inode / 3 blocks */ if ( req_nr_inodes == 0 ) - INODES = BLOCKS/3; + inodes = BLOCKS/3; else - INODES = req_nr_inodes; + inodes = req_nr_inodes; + if (inodes > 65535) + inodes = 65535; + INODES = inodes; /* I don't want some off-by-one errors, so this hack... */ if ((INODES & 8191) > 8188) INODES -= 5; @@ -345,6 +487,8 @@ void setup_tables(void) ZMAPS = 0; while (ZMAPS != UPPER(BLOCKS - NORM_FIRSTZONE,BITS_PER_BLOCK)) ZMAPS = UPPER(BLOCKS - NORM_FIRSTZONE,BITS_PER_BLOCK); + if (ZMAPS > 64) + die ("Filesystem too big for Linux to handle"); FIRSTZONE = NORM_FIRSTZONE; for (i = FIRSTZONE ; i<ZONES ; i++) unmark_zone(i); @@ -354,11 +498,11 @@ void setup_tables(void) if (!inode_buffer) die("unable to allocate buffer for inodes"); memset(inode_buffer,0,INODE_BUFFER_SIZE); - printf("%d inodes\n",INODES); - printf("%d blocks\n",ZONES); - printf("Firstdatazone=%d (%d)\n",FIRSTZONE,NORM_FIRSTZONE); + printf("%ld inodes\n",INODES); + printf("%ld blocks\n",ZONES); + printf("Firstdatazone=%ld (%ld)\n",FIRSTZONE,NORM_FIRSTZONE); printf("Zonesize=%d\n",BLOCK_SIZE<<ZONESIZE); - printf("Maxsize=%d\n\n",MAXSIZE); + printf("Maxsize=%ld\n\n",MAXSIZE); } /* @@ -431,116 +575,146 @@ void check_blocks(void) void get_list_blocks(filename) char *filename; -{ - FILE *listfile; - unsigned long blockno; - listfile=fopen(filename,"r"); - if(listfile == (FILE *)NULL) { - die("can't open file of bad blocks"); - } - while(!feof(listfile)) { - fscanf(listfile,"%d\n", &blockno); - mark_zone(blockno); - badblocks++; - } - if(badblocks) { - printf("%d bad block%s\n", badblocks, (badblocks>1)?"s":""); - } +{ + FILE *listfile; + unsigned long blockno; + + listfile=fopen(filename,"r"); + if(listfile == (FILE *)NULL) { + die("can't open file of bad blocks"); + } + while(!feof(listfile)) { + fscanf(listfile,"%ld\n", &blockno); + mark_zone(blockno); + badblocks++; + } + if(badblocks) { + printf("%d bad block%s\n", badblocks, (badblocks>1)?"s":""); + } } int main(int argc, char ** argv) + { - int i; - char * tmp; - struct stat statbuf; - char * listfile = NULL; - - if (argc && *argv) - program_name = *argv; - if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) - die("bad inode size"); - while (argc-- > 1) { - argv++; - if (argv[0][0] != '-') - if (device_name) { - BLOCKS = strtol(argv[0],&tmp,0); - if (*tmp) { - printf("strtol error: number of" - " blocks not specified"); - usage(); - } - } else - device_name = argv[0]; - else { - if(argv[0][1] == 'l') { - listfile = argv[1]; - argv++; - if (!(argc--)) - usage(); - } else { - if(argv[0][1] == 'i') { - req_nr_inodes - = (unsigned long)atol(argv[1]); - argv++; - if (!(argc--)) - usage(); - } else while (*(++argv[0])) { - switch (argv[0][0]) { - case 'c': check=1; break; - case 'n': - i = strtoul(argv[0]+1,&tmp,0); - if (*tmp) - usage(); - argv[0][1] = '\0'; - if (i == 14) - magic = MINIX_SUPER_MAGIC; - else if (i == 30) - magic = MINIX_SUPER_MAGIC2; - else - usage(); - namelen = i; - dirsize = i+2; - break; - default: usage(); - } - } - } - } + int i; + char * tmp; + struct stat statbuf; + char * listfile = NULL; + + if (argc && *argv) + program_name = *argv; + if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) + die("bad inode size"); +#ifdef HAVE_MINIX2 + if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) + die("bad inode size"); +#endif + while (argc-- > 1) { + argv++; + if (argv[0][0] != '-') + if (device_name) { + BLOCKS = strtol(argv[0],&tmp,0); + if (*tmp) { + printf("strtol error: number of" + " blocks not specified"); + usage(); } - if (!device_name || BLOCKS<10 || BLOCKS > 65536) { - usage(); + } else + device_name = argv[0]; + else { + if(argv[0][1] == 'l') { + listfile = argv[1]; + argv++; + if (!(argc--)) + usage(); + } else { + if(argv[0][1] == 'i') { + req_nr_inodes + = (unsigned long)atol(argv[1]); + argv++; + if (!(argc--)) + usage(); + } else while (*(++argv[0])) { + switch (argv[0][0]) { + case 'c': check=1; break; + case 'n': + i = strtoul(argv[0]+1,&tmp,0); + if (*tmp) + usage(); + argv[0][1] = '\0'; + if (i == 14) + magic = MINIX_SUPER_MAGIC; + else if (i == 30) + magic = MINIX_SUPER_MAGIC2; + else + usage(); + namelen = i; + dirsize = i+2; + break; + case 'v': +#ifdef HAVE_MINIX2 + version2 = 1; +#else + fatal_error("%s: not compiled with minix v2 support\n",-1); +#endif + break; + default: usage(); + } } - check_mount(); /* is it already mounted? */ - tmp = root_block; - tmp[0] = 1; - tmp[1] = 0; - strcpy(tmp+2,"."); - tmp += dirsize; - tmp[0] = 1; - tmp[1] = 0; - strcpy(tmp+2,".."); - tmp += dirsize; - tmp[0] = 2; - tmp[1] = 0; - strcpy(tmp+2,".badblocks"); - DEV = open(device_name,O_RDWR ); - if (DEV<0) - die("unable to open %s"); - if (fstat(DEV,&statbuf)<0) - die("unable to stat %s"); - if (!S_ISBLK(statbuf.st_mode)) - check=0; - else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) - die("will not try to make filesystem on '%s'"); - setup_tables(); - if (check) - check_blocks(); - else if (listfile) - get_list_blocks(listfile); - make_root_inode(); - make_bad_inode(); - mark_good_blocks(); - write_tables(); - return 0; + } + } + } + if (device_name && !BLOCKS) + BLOCKS = get_size (device_name) / 1024; + if (!device_name || BLOCKS<10) { + usage(); + } +#ifdef HAVE_MINIX2 + if (version2) { + if (namelen == 14) + magic = MINIX2_SUPER_MAGIC; + else + magic = MINIX2_SUPER_MAGIC2; + } else +#endif + if (BLOCKS > 65535) + BLOCKS = 65535; + check_mount(); /* is it already mounted? */ + tmp = root_block; + *(short *)tmp = 1; + strcpy(tmp+2,"."); + tmp += dirsize; + *(short *)tmp = 1; + strcpy(tmp+2,".."); + tmp += dirsize; + *(short *)tmp = 2; + strcpy(tmp+2,".badblocks"); + DEV = open(device_name,O_RDWR ); + if (DEV<0) + die("unable to open %s"); + if (fstat(DEV,&statbuf)<0) + die("unable to stat %s"); + if (!S_ISBLK(statbuf.st_mode)) + check=0; + else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) + die("will not try to make filesystem on '%s'"); + setup_tables(); + if (check) + check_blocks(); + else if (listfile) + get_list_blocks(listfile); +#ifdef HAVE_MINIX2 + if (version2) { + make_root_inode2 (); + make_bad_inode2 (); + } else +#endif + { + make_root_inode(); + make_bad_inode(); + } + mark_good_blocks(); + write_tables(); + return 0; } diff --git a/disk-utils/mkswap.8 b/disk-utils/mkswap.8 index 643d7ba04..1e14167b8 100644 --- a/disk-utils/mkswap.8 +++ b/disk-utils/mkswap.8 @@ -5,7 +5,7 @@ .\" Patches from jaggy@purplet.demon.co.uk (Mike Jagdis), Wed Feb 8 1995 .\" Added comments from Nick Holloway, Sat Feb 11 1995, faith@cs.unc.edu .\" " -.TH MKSWAP 8 "8 February 1995" "Linux 1.0" "Linux Programmer's Manual" +.TH MKSWAP 8 "February 1995" "Linux 1.0" "Linux Programmer's Manual" .SH NAME mkswap \- set up a Linux swap area .SH SYNOPSIS diff --git a/disk-utils/mkswap.c b/disk-utils/mkswap.c index fe3f04c11..2a4027406 100644 --- a/disk-utils/mkswap.c +++ b/disk-utils/mkswap.c @@ -24,9 +24,11 @@ #include <string.h> #include <fcntl.h> #include <stdlib.h> +#include <sys/ioctl.h> #include <sys/stat.h> +#include <asm/page.h> -#include <linux/mm.h> +#define BLKGETSIZE 0x1260 #ifndef __linux__ # define volatile @@ -43,7 +45,7 @@ static int badpages = 0; static int signature_page[PAGE_SIZE/sizeof(int)]; -static long bit_test_and_set (unsigned int *addr, unsigned int nr) +static void bit_set (unsigned int *addr, unsigned int nr) { unsigned int r, m; @@ -51,10 +53,9 @@ static long bit_test_and_set (unsigned int *addr, unsigned int nr) r = *addr; m = 1 << (nr & (8 * sizeof(int) - 1)); *addr = r | m; - return (r & m) != 0; } -static bit_test_and_clear (unsigned int *addr, unsigned int nr) +static int bit_test_and_clear (unsigned int *addr, unsigned int nr) { unsigned int r, m; @@ -88,18 +89,18 @@ void check_blocks(void) current_page = 0; while (current_page < PAGES) { if (!check) { - bit_test_and_set(signature_page,current_page++); + bit_set(signature_page,current_page++); continue; } if (do_seek && lseek(DEV,current_page*PAGE_SIZE,SEEK_SET) != current_page*PAGE_SIZE) die("seek failed in check_blocks"); - if (do_seek = (PAGE_SIZE != read(DEV, buffer, PAGE_SIZE))) { + if ((do_seek = (PAGE_SIZE != read(DEV, buffer, PAGE_SIZE)))) { bit_test_and_clear(signature_page,current_page++); badpages++; continue; } - bit_test_and_set(signature_page,current_page++); + bit_set(signature_page,current_page++); } if (badpages) printf("%d bad page%s\n",badpages,(badpages>1)?"s":""); @@ -183,7 +184,13 @@ int main(int argc, char ** argv) if (device_name && !PAGES) { PAGES = get_size(device_name) / PAGE_SIZE; } - if (!device_name || PAGES<10) { + if (!device_name) { + fprintf(stderr, + "%s: error: Nowhere to set up swap on?\n", + program_name); + usage(); + } + if (PAGES < 10) { fprintf(stderr, "%s: error: swap area needs to be at least %ldkB\n", program_name, 10 * PAGE_SIZE / 1024); @@ -209,8 +216,9 @@ int main(int argc, char ** argv) goodpages = PAGES - badpages - 1; if (goodpages <= 0) die("Unable to set up swap-space: unreadable"); - printf("Setting up swapspace, size = %d bytes\n",goodpages*PAGE_SIZE); - strncpy((char*)signature_page+PAGE_SIZE-10,"SWAP-SPACE",10); + printf("Setting up swapspace, size = %ld bytes\n", + goodpages*PAGE_SIZE); + strncpy((char*)signature_page+PAGE_SIZE-10, "SWAP-SPACE", 10); if (lseek(DEV, 0, SEEK_SET)) die("unable to rewind swap-device"); if (PAGE_SIZE != write(DEV, signature_page, PAGE_SIZE)) diff --git a/disk-utils/setfdprm.c b/disk-utils/setfdprm.c index bd98f5a2f..fee55300d 100644 --- a/disk-utils/setfdprm.c +++ b/disk-utils/setfdprm.c @@ -2,11 +2,13 @@ autodetection and switches diagnostic messages. */ #include <unistd.h> +#include <stdlib.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> +#include <sys/ioctl.h> #include <linux/fd.h> #define FDPRMFILE "/etc/fdprm" @@ -89,7 +91,7 @@ static void usage(char *name) { char *this; - if (this = strrchr(name,'/')) name = this+1; + if ((this = strrchr(name,'/')) != NULL) name = this+1; fprintf(stderr,"usage: %s [ -p ] dev name\n",name); fprintf(stderr," %s [ -p ] dev size sect heads tracks stretch \ gap rate spec1 fmt_gap\n",name); @@ -101,10 +103,11 @@ gap rate spec1 fmt_gap\n",name); exit(1); } - +void main(int argc,char **argv) { - int cmd,fd; + int fd; + unsigned int cmd; char *name; name = argv[0]; @@ -143,7 +146,11 @@ main(int argc,char **argv) if (argc != 2) usage(name); cmd_without_param(cmd,fd); } - if (argc != 11 && argc != 3) usage(name); - if (argc == 11) set_params(cmd,fd,&argv[2]); - else find_params(cmd,fd,argv[2]); + if (argc != 11 && argc != 3) + usage(name); + else if (argc == 11) + set_params(cmd,fd,&argv[2]); + else + find_params(cmd,fd,argv[2]); + /* not reached */ } diff --git a/disk-utils/sfdisk.8 b/disk-utils/sfdisk.8 new file mode 100644 index 000000000..fc9308013 --- /dev/null +++ b/disk-utils/sfdisk.8 @@ -0,0 +1,497 @@ +.\" Copyright 1995 Andries E. Brouwer (aeb@cwi.nl) +.\" May be distributed under the GNU General Public License +.\" The `DOS 6.x Warning' was taken from the old fdisk.8, which says +.\" -- Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu) +.\" -- May be distributed under the GNU General Public License +.\" The `DRDOS Warning' was taken from a net post by Stephen Tweedie. +.\" +.TH SFDISK 8 "1 September 1995" "Linux 1.3.23" "Linux Programmer's Manual" +.SH NAME +sfdisk \- Partition table manipulator for Linux +.SH SYNOPSIS +.BR sfdisk " [options] device" +.br +.BR "sfdisk \-s " [partition] +.SH DESCRIPTION +.B sfdisk +has four (main) uses: list the size of a partition, list the partitions +on a device, check the partitions on a device, and - very dangerous - +repartition a device. + +.SS "List Sizes" +.BI "sfdisk \-s " partition +gives the size of +.I partition +in blocks. This may be useful in connection with programs like +.B mkswap +or so. Here +.I partition +is usually something like +.I /dev/hda1 +or +.IR /dev/sdb12 , +but may also be an entire disk, like +.IR /dev/xda . +.br +.RS +.nf +.if t .ft CW +% sfdisk \-s /dev/hda9 +81599 +% +.if t .ft R +.fi +.RE +If the partition argument is omitted, +.B sfdisk +will list the sizes of all disks, and the total: +.br +.RS +.nf +.if t .ft CW +% sfdisk \-s +/dev/hda: 208896 +/dev/hdb: 1025136 +/dev/hdc: 1031063 +/dev/sda: 8877895 +/dev/sdb: 1758927 +total: 12901917 blocks +% +.if t .ft R +.fi +.RE + +.SS "List Partitions" +The second type of invocation: +.BI "sfdisk \-l " "[options] device" +will list the partitions on this device. +If the device argument is omitted, the partitions on all hard disks +are listed. +.br +.nf +.if t .ft CW +% sfdisk \-l /dev/hdc + +Disk /dev/hdc: 16 heads, 63 sectors, 2045 cylinders +Units = cylinders of 516096 bytes, blocks of 1024 bytes, counting from 0 + + Device Boot Start End #cyls #blocks Id System +/dev/hdc1 0+ 406 407\- 205096+ 83 Linux native +/dev/hdc2 407 813 407 205128 83 Linux native +/dev/hdc3 814 2044 1231 620424 83 Linux native +/dev/hdc4 0 \- 0 0 0 Empty +% +.if t .ft R +.fi +The trailing \- and + signs indicate that rounding has taken place, +and that the actual value is slightly less (more). +To see the exact values, ask for a listing with sectors as unit. + +.SS "Check partitions" +The third type of invocation: +.BI "sfdisk \-V " device +will apply various consistency checks to the partition tables on +.IR device . +It prints `OK' or complains. The \-V option can be used together +with \-l. In a shell script one might use +.BI "sfdisk \-V \-q " device +which only returns a status. + +.SS "Create partitions" +The fourth type of invocation: +.BI "sfdisk " device +will cause +.B sfdisk +to read the specification for the desired partitioning of +.I device +from its standard input, and then to change the partition tables +on that disk. Thus, it is possible to use +.B sfdisk +from a shell script. When +.B sfdisk +determines that its standard input is a terminal, it will be +conversational; otherwise it will abort on any error. +.LP +BE EXTREMELY CAREFUL - ONE TYPING MISTAKE AND ALL YOUR DATA IS LOST +.LP +As a precaution, one can save the sectors changed by +.BR sfdisk : +.RS +.nf +.if t .ft CW +% sfdisk /dev/hdd \-O hdd-partition-sectors.save +% +.if t .ft R +.fi +.RE +.LP +Then, if you discover that you did something stupid before anything +else has been written to disk, it may be possible to recover +the old situation with +.RS +.nf +.if t .ft CW +% sfdisk /dev/hdd \-I hdd-partition-sectors.save +% +.if t .ft R +.fi +.RE + +There are many options. + +.SH OPTIONS +.TP +.BR \-v " or " \-\-version +Print version number of +.B sfdisk +and exit immediately. +.TP +.BR \-? " or " \-\-help +Print a usage message and exit immediately. +.TP +.BR \-T " or " \-\-list-types +Print the recognized types (system Id's). +.TP +.BR \-s " or " \-\-show\-size +List the size of a partition. +.TP +.BR \-g " or " \-\-show\-geometry +List the kernel's idea of the geometry of the indicated disk(s). +.TP +.BR \-l " or " \-\-list +List the partitions of a device. +.TP +.BR \-d +Dump the partitions of a device in a format useful as input +to sfdisk. For example, +.br +.nf +.if t .ft CW + % sfdisk -d /dev/hda > hda.out + % sfdisk /dev/hda < hda.out +.if t .ft R +.fi +will correct the bad last extended partition that the OS/2 +sfdisk creates. +.TP +.BR \-V " or " \-\-verify +Test whether partitions seem correct. (See above.) +.TP +.BR \-i " or " \-\-increment +Number cylinders etc. starting from 1 instead of 0. +.TP +.BI \-N " number" +Change only the single partition indicated. For example: +.br +.nf +.if t .ft CW + % sfdisk /dev/hdb \-N5 + ,,,* + % +.if t .ft R +.fi +will make the fifth partition on /dev/hdb bootable (`active') +and change nothing else. (Probably this fifth partition +is called /dev/hdb5, but you are free to call it something else, +like `/my_equipment/disks/2/5' or so). +.TP +.BI \-A " number" +Make the indicated partition(s) active, and all others inactive. +.TP +.BI \-c " or " \-\-id " number [Id]" +If no Id argument given: print the partition Id of the indicated +partition. If an Id argument is present: change the type (Id) of +the indicated partition to the given value. +This option has the two very long forms \-\-print\-id and \-\-change\-id. +For example: +.br +.nf +.if t .ft CW + % sfdisk --print-id /dev/hdb 5 + 6 + % sfdisk --change-id /dev/hdb 5 83 + OK +.if t .ft R +.fi +first reports that /dev/hdb5 has Id 6, and then changes that into 83. +.TP +.BR \-uS " or " \-uB " or " \-uC " or " \-uM +Accept or report in units of sectors (blocks, cylinders, megabytes, +respectively). The default is cylinders, at least when the geometry +is known. +.TP +.BR \-x " or " \-\-show\-extended +Also list non-primary extended partitions on output, +and expect descriptors for them on input. +.TP +.BI \-C " cylinders" +Specify the number of cylinders, possibly overriding what the kernel thinks. +.TP +.BI \-H " heads" +Specify the number of heads, possibly overriding what the kernel thinks. +.TP +.BI \-S " sectors" +Specify the number of sectors, possibly overriding what the kernel thinks. +.TP +.BR \-f " or " \-\-force +Do what I say, even if it is stupid. +.TP +.BR \-q " or " \-\-quiet +Suppress warning messages. +.TP +.BR \-L " or " \-\-Linux +Do not complain about things irrelevant for Linux. +.TP +.BR \-D " or " \-\-DOS +For DOS-compatibility: waste a little space. +(More precisely: if a partition cannot contain sector 0, +e.g. because that is the MBR of the device, or contains +the partition table of an extended partition, then +.B sfdisk +would make it start the next sector. However, when this +option is given it skips to the start of the next track, +wasting for example 33 sectors (in case of 34 sectors/track), +just like certain versions of DOS do.) +Certain Disk Managers and boot loaders (such as OSBS, but not +LILO or the OS/2 Boot Manager) also live in this empty space, +so maybe you want this option if you use one. +.TP +.BR \-\-IBM " or " \-\-leave\-last +Certain IBM diagnostic programs assume that they can use the +last cylinder on a disk for disk-testing purposes. If you think +you might ever run such programs, use this option to tell +.B sfdisk +that it should not allocate the last cylinder. +Sometimes the last cylinder contains a bad sector table. +.TP +.B \-n +Go through all the motions, but do not actually write to disk. +.TP +.B \-R +Only execute the BLKRRPART ioctl (to make the kernel re-read +the partition table). This can be useful for checking in advance +that the final BLKRRPART will be successful, and also when you +changed the partition table `by hand' (e.g., using dd from a backup). +If the kernel complains (`device busy for revalidation (usage = 2)') +then something still uses the device, and you still have to unmount +some file system, or say swapoff to some swap partition. +.TP +.B \-\-no\-reread +When starting a repartitioning of a disk, sfdisk checks that this disk +is not mounted, or in use as a swap device, and refuses to continue +if it is. This option suppresses the test. (On the other hand, the \-f +option would force sfdisk to continue even when this test fails.) +.TP +.BI \-O " file" +Just before writing the new partition, output the sectors +that are going to be overwritten to +.I file +(where hopefully +.I file +resides on another disk, or on a floppy). +.TP +.BI \-I " file" +After destroying your filesystems with an unfortunate +.B sfdisk +command, you would have been able to restore the old situation +if only you had preserved it using the \-O flag. + +.SH THEORY +Block 0 of a disk (the Master Boot Record) contains among +other things four partition descriptors. The partitions +described here are called +.I primary +partitions. +.LP +A partition descriptor has 6 fields: +.br +.nf +.RS +struct partition { + unsigned char bootable; /* 0 or 0x80 */ + hsc begin_hsc; + unsigned char id; + hsc end_hsc; + unsigned int starting_sector; + unsigned int nr_of_sectors; +} +.RE +.fi +.LP +The two hsc fields indicate head, sector and cylinder of the +begin and the end of the partition. Since each hsc field only +takes 3 bytes, only 24 bits are available, which does not +suffice for big disks (say > 8GB). In fact, due to the wasteful +representation (that uses a byte for the number of heads, which +is typically 16), problems already start with 0.5GB. +However Linux does not use these fields, and problems can arise +only at boot time, before Linux has been started. For more +details, see the +.B lilo +documentation. +.LP +Each partition has a type, its `Id', and if this type is 5 +.IR "" "(`" "extended partition" "')" +the starting sector of the partition +again contains 4 partition descriptors. MSDOS only uses the +first two of these: the first one an actual data partition, +and the second one again an extended partition (or empty). +In this way one gets a chain of extended partitions. +Other operating systems have slightly different conventions. +Linux also accepts type 85 as equivalent to 5 - this can be +useful if one wants to have extended partitions under Linux past +the 1024 cylinder boundary, without DOS FDISK hanging. +(If there is no good reason, you should just use 5, which is +understood by other systems.) +.LP +Partitions that are not primary or extended are called +.IR logical . +Often, one cannot boot from logical partitions (because the +process of finding them is more involved than just looking +at the MBR). +Note that of an extended partition only the Id and the start +are used. There are various conventions about what to write +in the other fields. One should not try to use extended partitions +for data storage or swap. + +.SH "INPUT FORMAT" +.B sfdisk +reads lines of the form +.br +.RS +<start> <size> <id> <bootable> <c,h,s> <c,h,s> +.RE +where each line fills one partition descriptor. +.LP +Fields are separated by whitespace, or comma or semicolon possibly +followed by whitespace; initial and trailing whitespace is ignored. +Numbers can be octal, decimal or hexadecimal, decimal is default. +When a field is absent or empty, a default value is used. +.LP +The <c,h,s> parts can (and probably should) be omitted - +.B sfdisk +computes them from <start> and <size> and the disk geometry +as given by the kernel or specified using the \-H, \-S, \-C flags. +.LP +Bootable is specified as [*|\-], with as default not-bootable. +(The value of this field is irrelevant for Linux - when Linux +runs it has been booted already - but might play a role for +certain boot loaders and for other operating systems. +For example, when there are several primary DOS partitions, +DOS assigns C: to the first among these that is bootable.) +.LP +Id is given in hex, without the 0x prefix, or is [E|S|L|X], where +L (LINUX_NATIVE (83)) is the default, S is LINUX_SWAP (82), E +is EXTENDED_PARTITION (5), and X is LINUX_EXTENDED (85). +.LP +The default value of start is the first nonassigned sector/cylinder/... +.LP +The default value of size is as much as possible (until next +partition or end-of-disk). +.LP +However, for the four partitions inside an extended partition, +the defaults are: Linux partition, Extended partition, Empty, Empty. +.LP +But when the \-N option (change a single partition only) is given, +the default for each field is its previous value. + +.SH EXAMPLE +The command +.RS +.nf +.if t .ft CW +sfdisk /dev/hdc << EOF +0,407 +,407 +; +; +EOF +.if t .ft R +.fi +.RE +will partition /dev/hdc just as indicated above. + +With the \-x option, the number of input lines must be a multiple of 4: +you have to list the two empty partitions that you never want +using two blank lines. Without the \-x option, you give one line +for the partitions inside a extended partition, instead of four, +and terminate with end-of-file (^D). +(And +.B sfdisk +will assume that your input line represents the first of four, +that the second one is extended, and the 3rd and 4th are empty.) + +.SH "DOS 6.x WARNING" + +The DOS 6.x FORMAT command looks for some information in the first +sector of the data area of the partition, and treats this information +as more reliable than the information in the partition table. DOS +FORMAT expects DOS FDISK to clear the first 512 bytes of the data area +of a partition whenever a size change occurs. DOS FORMAT will look at +this extra information even if the /U flag is given -- we consider +this a bug in DOS FORMAT and DOS FDISK. +.LP +The bottom line is that if you use sfdisk to change the size of a +DOS partition table entry, then you must also use +.B dd +to zero the first 512 bytes of that partition before using DOS FORMAT to +format the partition. For example, if you were using sfdisk to make a DOS +partition table entry for /dev/hda1, then (after exiting sfdisk and +rebooting Linux so that the partition table information is valid) you +would use the command "dd if=/dev/zero of=/dev/hda1 bs=512 count=1" to zero +the first 512 bytes of the partition. +.B BE EXTREMELY CAREFUL +if you use the +.B dd +command, since a small typo can make all of the data on your disk useless. + +For best results, you should always use an OS-specific partition table +program. For example, you should make DOS partitions with the DOS FDISK +program and Linux partitions with the Linux sfdisk program. + +.SH "DRDOS WARNINGS" + +Stephen Tweedie reported (930515): `Most reports of superblock +corruption turn out to be due to bad partitioning, with one filesystem +overrunning the start of the next and corrupting its superblock. +I have even had this problem with the supposedly-reliable DRDOS. This +was quite possibly due to DRDOS-6.0's FDISK command. Unless I created +a blank track or cylinder between the DRDOS partition and the +immediately following one, DRDOS would happily stamp all over the +start of the next partition. Mind you, as long as I keep a little +free disk space after any DRDOS partition, I don't have any other +problems with the two coexisting on the one drive.' + +A. V. Le Blanc writes in README.esfdisk: `Dr. DOS 5.0 and 6.0 has been +reported to have problems cooperating with Linux, and with this version +of efdisk in particular. This efdisk sets the system type +to hexadecimal 81. Dr. DOS seems to confuse +this with hexadecimal 1, a DOS code. If you use Dr. DOS, use the +efdisk command 't' to change the system code of any Linux partitions +to some number less than hexadecimal 80; I suggest 41 and 42 for +the moment.' + +A. V. Le Blanc writes in his README.fdisk: `DR-DOS 5.0 and 6.0 +are reported to have difficulties with partition ID codes of 80 or more. +The Linux `fdisk' used to set the system type +of new partitions to hexadecimal 81. DR-DOS seems to confuse this with +hexadecimal 1, a DOS code. The values 82 for swap and 83 for file +systems should not cause problems with DR-DOS. If they do, you may use +the `fdisk' command `t' to change the system code of any Linux +partitions to some number less than hexadecimal 80; I suggest 42 and 43 +for the moment.' + +In fact, it seems that only 4 bits are significant for the DRDOS FDISK, +so that for example 11 and 21 are listed as DOS 2.0. However, DRDOS +itself seems to use the full byte. I have not been able to reproduce +any corruption with DRDOS or its fdisk. + +.SH BUGS +A corresponding interactive +.B cfdisk +(with curses interface) is still lacking. +.LP +There are too many options. + +.SH AUTHOR +A. E. Brouwer (aeb@cwi.nl) diff --git a/disk-utils/sfdisk.c b/disk-utils/sfdisk.c new file mode 100644 index 000000000..fcc76c41c --- /dev/null +++ b/disk-utils/sfdisk.c @@ -0,0 +1,2712 @@ +/* + * sfdisk version 3.0 - aeb - 950813 + * + * Copyright (C) 1995 Andries E. Brouwer (aeb@cwi.nl) + * + * 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. + * + * A.V. Le Blanc (LeBlanc@mcc.ac.uk) wrote Linux fdisk 1992-1994, + * patched by various people (faith@cs.unc.edu, martin@cs.unc.edu, + * leisner@sdsp.mc.xerox.com, esr@snark.thyrsus.com, aeb@cwi.nl) + * 1993-1995, with version numbers (as far as I have seen) 0.93 - 2.0e. + * This program had (head,sector,cylinder) as basic unit, and was + * (therefore) broken in several ways for the use on larger disks - + * for example, my last patch (from 2.0d to 2.0e) was required + * to allow a partition to cross cylinder 8064, and to write an + * extended partition past the 4GB mark. + * + * The current program is a rewrite from scratch, and I started a + * version numbering at 3.0. + * Andries Brouwer, aeb@cwi.nl, 950813 + * + * Well, a good user interface is still lacking. On the other hand, + * many configurations cannot be handled by any other fdisk. + * I changed the name to sfdisk to prevent confusion. - aeb, 970501 + */ + +#define PROGNAME "sfdisk" +#define VERSION "3.06" +#define DATE "970626" + +#include <stdio.h> +#include <stdlib.h> /* atoi, free */ +#include <stdarg.h> /* varargs */ +#include <unistd.h> /* read, write */ +#include <fcntl.h> /* O_RDWR */ +#include <errno.h> /* ERANGE */ +#include <string.h> /* index() */ +#include <ctype.h> +#include <getopt.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <linux/unistd.h> /* _syscall */ +#include <linux/hdreg.h> /* HDIO_GETGEO */ +#include <linux/fs.h> /* BLKGETSIZE */ + +#define SIZE(a) (sizeof(a)/sizeof(a[0])) + +/* + * Table of contents: + * A. About seeking + * B. About sectors + * C. About heads, sectors and cylinders + * D. About system Ids + * E. About partitions + * F. The standard input + * G. The command line + * H. Listing the current situation + * I. Writing the new situation + */ +int exit_status = 0; + +int force = 0; /* 1: do what I say, even if it is stupid ... */ +int quiet = 0; /* 1: suppress all warnings */ +int Linux = 0; /* 1: suppress warnings irrelevant for Linux */ +int DOS = 0; /* 1: shift extended partitions by #sectors, not 1 */ +int dump = 0; /* 1: list in a format suitable for later input */ +int verify = 0; /* 1: check that listed partition is reasonable */ +int no_write = 0; /* 1: do not actually write to disk */ +int no_reread = 0; /* 1: skip the BLKRRPART ioctl test at startup */ +int leave_last = 0; /* 1: don't allocate the last cylinder */ +int opt_list = 0; +char *save_sector_file = NULL; +char *restore_sector_file = NULL; + +void +warn(char *s, ...) { + va_list p; + + va_start(p, s); + fflush(stdout); + if (!quiet) + vfprintf (stderr, s, p); + va_end(p); +} + +void +error(char *s, ...) { + va_list p; + + va_start(p, s); + fflush(stdout); + fprintf(stderr, "\n" PROGNAME ": "); + vfprintf(stderr, s, p); + va_end(p); +} + +void +fatal(char *s, ...) { + va_list p; + + va_start(p, s); + fflush(stdout); + fprintf(stderr, "\n" PROGNAME ": "); + vfprintf(stderr, s, p); + va_end(p); + exit(1); +} + +/* + * A. About seeking + */ + +/* + * sseek: seek to specified sector - return 0 on failure + * + * For >4GB disks lseek needs a > 32bit arg, and we have to use llseek. + * On the other hand, a 32 bit sector number is OK until 2TB. + * The routines _llseek and sseek below are the only ones that + * know about the loff_t type. + */ +#ifndef __alpha__ +static +_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, + loff_t *, res, uint, wh); +#endif + +int +sseek(char *dev, unsigned int fd, unsigned long s) { + loff_t in, out; + in = ((loff_t) s << 9); + out = 1; + +#ifndef __alpha__ + if (_llseek (fd, in>>32, in & 0xffffffff, &out, SEEK_SET) != 0) { +#else + if ((out = lseek(fd, in, SEEK_SET)) != in) { +#endif + perror("llseek"); + error("seek error on %s - cannot seek to %lu\n", dev, s); + return 0; + } + + if (in != out) { + error("seek error: wanted 0x%08x%08x, got 0x%08x%08x\n", + (uint)(in>>32), (uint)(in & 0xffffffff), + (uint)(out>>32), (uint)(out & 0xffffffff)); + return 0; + } + return 1; +} + +/* + * B. About sectors + */ + +/* + * We preserve all sectors read in a chain - some of these will + * have to be modified and written back. + */ +struct sector { + struct sector *next; + unsigned long sectornumber; + int to_be_written; + char data[512]; +} *sectorhead; + +void +free_sectors(void) { + struct sector *s; + + while (sectorhead) { + s = sectorhead; + sectorhead = s->next; + free(s); + } +} + +struct sector * +get_sector(char *dev, int fd, unsigned long sno) { + struct sector *s; + + for(s = sectorhead; s; s = s->next) + if(s->sectornumber == sno) + return s; + + if (!sseek(dev, fd, sno)) + return 0; + + if (!(s = (struct sector *) malloc(sizeof(struct sector)))) + fatal("out of memory - giving up\n"); + + if (read(fd, s->data, sizeof(s->data)) != sizeof(s->data)) { + perror("read"); + error("read error on %s - cannot read sector %lu\n", dev, sno); + free(s); + return 0; + } + + s->next = sectorhead; + sectorhead = s; + s->sectornumber = sno; + s->to_be_written = 0; + + return s; +} + +int +msdos_signature (struct sector *s) { + if (*(unsigned short *) (s->data + 0x1fe) != 0xaa55) { + error("ERROR: sector %lu does not have an msdos signature\n", + s->sectornumber); + return 0; + } + return 1; +} + +int +write_sectors(char *dev, int fd) { + struct sector *s; + + for (s = sectorhead; s; s = s->next) + if (s->to_be_written) { + if (!sseek(dev, fd, s->sectornumber)) + return 0; + if (write(fd, s->data, sizeof(s->data)) != sizeof(s->data)) { + perror("write"); + error("write error on %s - cannot write sector %lu\n", + dev, s->sectornumber); + return 0; + } + s->to_be_written = 0; + } + return 1; +} + +void +ulong_to_chars(unsigned long u, char *uu) { + int i; + + for(i=0; i<4; i++) { + uu[i] = (u & 0xff); + u >>= 8; + } +} + +unsigned long +chars_to_ulong(unsigned char *uu) { + int i; + unsigned long u = 0; + + for(i=3; i>=0; i--) + u = (u << 8) | uu[i]; + return u; +} + +int +save_sectors(char *dev, int fdin) { + struct sector *s; + char ss[516]; + int fdout; + + fdout = open(save_sector_file, O_WRONLY | O_CREAT, 0444); + if (fdout < 0) { + perror(save_sector_file); + error("cannot open partition sector save file (%s)\n", + save_sector_file); + return 0; + } + + for (s = sectorhead; s; s = s->next) + if (s->to_be_written) { + ulong_to_chars(s->sectornumber, ss); + if (!sseek(dev, fdin, s->sectornumber)) + return 0; + if (read(fdin, ss+4, 512) != 512) { + perror("read"); + error("read error on %s - cannot read sector %lu\n", + dev, s->sectornumber); + return 0; + } + if (write(fdout, ss, sizeof(ss)) != sizeof(ss)) { + perror("write"); + error("write error on %s\n", save_sector_file); + return 0; + } + } + return 1; +} + +void reread_disk_partition(char *dev, int fd); + +int +restore_sectors(char *dev) { + int fdin, fdout, ct; + struct stat statbuf; + char *ss0, *ss; + unsigned long sno; + + if (stat(restore_sector_file, &statbuf) < 0) { + perror(restore_sector_file); + error("cannot stat partition restore file (%s)\n", + restore_sector_file); + return 0; + } + if (statbuf.st_size % 516) { + error("partition restore file has wrong size - not restoring\n"); + return 0; + } + if (!(ss = (char *) malloc(statbuf.st_size))) { + error("out of memory?\n"); + return 0; + } + fdin = open(restore_sector_file, O_RDONLY); + if (fdin < 0) { + perror(restore_sector_file); + error("cannot open partition restore file (%s)\n", + restore_sector_file); + return 0; + } + if (read(fdin, ss, statbuf.st_size) != statbuf.st_size) { + perror("read"); + error("error reading %s\n", restore_sector_file); + return 0; + } + + fdout = open(dev, O_WRONLY); + if (fdout < 0) { + perror(dev); + error("cannot open device %s for writing\n", dev); + return 0; + } + + ss0 = ss; + ct = statbuf.st_size/516; + while(ct--) { + sno = chars_to_ulong(ss); + if (!sseek(dev, fdout, sno)) + return 0; + if (write(fdout, ss+4, 512) != 512) { + perror(dev); + error("error writing sector %lu on %s\n", sno, dev); + return 0; + } + ss += 516; + } + free(ss0); + + reread_disk_partition(dev, fdout); + + return 1; +} + +/* + * C. About heads, sectors and cylinders + */ + +/* + * <linux/hdreg.h> defines HDIO_GETGEO and + * struct hd_geometry { + * unsigned char heads; + * unsigned char sectors; + * unsigned short cylinders; + * unsigned long start; + * }; + */ + +unsigned long cylindersize; +unsigned long heads, sectors, cylinders; +unsigned long specified_heads, specified_sectors, specified_cylinders; + +void +get_cylindersize(char *dev, int fd, int silent) { + struct hd_geometry g; + int ioctl_ok = 0; + + heads = sectors = cylinders = 0; + + if (!ioctl(fd, HDIO_GETGEO, &g)) { + ioctl_ok = 1; + + heads = g.heads; + sectors = g.sectors; + cylinders = g.cylinders; + } + + if (specified_heads) + heads = specified_heads; + if (specified_sectors) + sectors = specified_sectors; + if (specified_cylinders) + cylinders = specified_cylinders; + + cylindersize = heads * sectors; + + if (ioctl_ok) { + if (g.start && !force) { + warn( + "Warning: start=%d - this looks like a partition rather than\n" + "the entire disk. Using fdisk on it is probably meaningless.\n" + "[Use the --force option if you really want this]\n", g.start); + exit(1); + } + if (heads != g.heads) + warn("Warning: HDIO_GETGEO says that there are %d heads\n", + g.heads); + if (sectors != g.sectors) + warn("Warning: HDIO_GETGEO says that there are %d sectors\n", + g.sectors); + if (cylinders != g.cylinders) + warn("Warning: HDIO_GETGEO says that there are %d cylinders\n", + g.cylinders); + } else if (!silent) + if (!heads || !sectors || !cylinders) + printf("Disk %s: cannot get geometry\n", dev); + if (sectors > 63) + warn("Warning: unlikely number of sectors (%d) - usually at most 63\n" + "This will give problems with all software that uses C/H/S addressing.\n", + sectors); + if (!silent) + printf("\nDisk %s: %lu heads, %lu sectors, %lu cylinders\n", + dev, heads, sectors, cylinders); +} + +typedef struct { unsigned char h,s,c; } chs; /* has some c bits in s */ +chs zero_chs = { 0,0,0 }; + +typedef struct { unsigned long h,s,c; } longchs; +longchs zero_longchs; + +chs +longchs_to_chs (longchs aa) { + chs a; + + if (aa.h < 256 && aa.s < 64 && aa.c < 1024) { + a.h = aa.h; + a.s = aa.s | ((aa.c >> 2) & 0xc0); + a.c = (aa.c & 0xff); + } else if (heads && sectors) { + a.h = heads - 1; + a.s = sectors | 0xc0; + a.c = 0xff; + } else + a = zero_chs; + return a; +} + +longchs +chs_to_longchs (chs a) { + longchs aa; + + aa.h = a.h; + aa.s = (a.s & 0x3f); + aa.c = (a.s & 0xc0); + aa.c = (aa.c << 2) + a.c; + return aa; +} + +longchs +ulong_to_longchs (unsigned long sno) { + longchs aa; + + if (heads && sectors && cylindersize) { + aa.s = 1 + sno % sectors; + aa.h = (sno / sectors) % heads; + aa.c = sno / cylindersize; + return aa; + } else { + return zero_longchs; + } +} + +unsigned long +longchs_to_ulong (longchs aa) { + return (aa.c*cylindersize + aa.h*sectors + aa.s - 1); +} + +chs +ulong_to_chs (unsigned long sno) { + return longchs_to_chs(ulong_to_longchs(sno)); +} + +unsigned long +chs_to_ulong (chs a) { + return longchs_to_ulong(chs_to_longchs(a)); +} + +int +is_equal_chs (chs a, chs b) { + return (a.h == b.h && a.s == b.s && a.c == b.c); +} + +int +chs_ok (chs a, char *v, char *w) { + longchs aa = chs_to_longchs(a); + int ret = 1; + + if (is_equal_chs(a, zero_chs)) + return 1; + if (heads && aa.h >= heads) { + warn("%s of partition %s has impossible value for head: " + "%d (should be in 0-%d)\n", w, v, aa.h, heads-1); + ret = 0; + } + if (sectors && (aa.s == 0 || aa.s > sectors)) { + warn("%s of partition %s has impossible value for sector: " + "%d (should be in 1-%d)\n", w, v, aa.s, sectors); + ret = 0; + } + if (cylinders && aa.c >= cylinders) { + warn("%s of partition %s has impossible value for cylinders: " + "%d (should be in 0-%d)\n", w, v, aa.c, cylinders-1); + ret = 0; + } + return ret; +} + +/* + * D. About system Ids + */ + +#define EMPTY_PARTITION 0 +#define EXTENDED_PARTITION 5 +#define DM6_PARTITION 0x54 +#define EZD_PARTITION 0x55 +#define DM6_AUX1PARTITION 0x51 +#define DM6_AUX3PARTITION 0x53 +#define LINUX_SWAP 0x82 +#define LINUX_NATIVE 0x83 +#define LINUX_EXTENDED 0x85 + +/* + * List of system Id's, adapted from fdisk 2.0d and <linux/genhd.h> + * and SFS and several other sources. + */ +struct systypes { + unsigned char type; + char *name; +} sys_types[] = { + {0, "Empty"}, + {1, "DOS 12-bit FAT"}, /* Primary DOS with 12-bit FAT */ + {2, "XENIX /"}, /* XENIX / filesystem */ + {3, "XENIX /usr"}, /* XENIX /usr filesystem */ + {4, "DOS 16-bit FAT <32M"}, /* Primary DOS with 16-bit FAT */ + {5, "DOS Extended"}, /* DOS 3.3+ extended partition */ + {6, "DOS 16-bit FAT >=32M"}, + {7, "HPFS / NTFS"}, + {8, "AIX boot or SplitDrive"}, + {9, "AIX data or Coherent"}, + {0x0a, "OS/2 Boot Manager"}, + {0x0b, "Win95 FAT32"}, + {0x0c, "Win95 FAT32 (LBA)"}, + {0x0e, "Win95 FAT16 (LBA)"}, + {0x0f, "Win95 Extended (LBA)"}, + {0x10, "OPUS"}, + {0x11, "Hidden DOS FAT12"}, + {0x12, "Compaq diagnostics"}, + {0x14, "Hidden DOS FAT16"}, + {0x16, "Hidden DOS FAT16 (big)"}, + {0x17, "Hidden HPFS/NTFS"}, + {0x18, "AST Windows swapfile"}, + {0x24, "NEC DOS"}, + {0x3c, "PartitionMagic recovery"}, + {0x40, "Venix 80286"}, + {0x41, "Linux/MINIX (sharing disk with DRDOS)"}, + {0x42, "SFS or Linux swap (sharing disk with DRDOS)"}, + {0x43, "Linux native (sharing disk with DRDOS)"}, + {0x50, "DM (disk manager)"}, + {0x51, "DM6 Aux1 (or Novell)"}, + {0x52, "CP/M or Microport SysV/AT"}, + {0x53, "DM6 Aux3"}, + {0x54, "DM6"}, + {0x55, "EZ-Drive (disk manager)"}, + {0x56, "Golden Bow (disk manager)"}, + {0x5c, "Priam Edisk (disk manager)"}, + {0x61, "SpeedStor"}, + {0x63, "GNU HURD or Mach or Sys V/386 (such as ISC UNIX)"}, + {0x64, "Novell Netware 286"}, + {0x65, "Novell Netware 386"}, + {0x70, "DiskSecure Multi-Boot"}, + {0x75, "PC/IX"}, + {0x77, "QNX4.x"}, + {0x78, "QNX4.x 2nd part"}, + {0x79, "QNX4.x 3rd part"}, + {0x80, "MINIX until 1.4a"}, + {0x81, "MINIX / old Linux"}, + {0x82, "Linux swap"}, + {0x83, "Linux native"}, + {0x84, "OS/2 hidden C: drive"}, + {0x85, "Linux extended"}, + {0x86, "NTFS volume set"}, + {0x87, "NTFS volume set"}, + {0x93, "Amoeba"}, + {0x94, "Amoeba BBT"}, /* (bad block table) */ + {0xa0, "IBM Thinkpad hibernation"}, /* according to dan@fch.wimsey.bc.ca */ + {0xa5, "BSD/386"}, /* 386BSD */ + {0xa7, "NeXTSTEP 486"}, + {0xb7, "BSDI fs"}, + {0xb8, "BSDI swap"}, + {0xc1, "DRDOS/sec (FAT-12)"}, + {0xc4, "DRDOS/sec (FAT-16, < 32M)"}, + {0xc6, "DRDOS/sec (FAT-16, >= 32M)"}, + {0xc7, "Syrinx"}, + {0xdb, "CP/M or Concurrent CP/M or Concurrent DOS or CTOS"}, + {0xe1, "DOS access or SpeedStor 12-bit FAT extended partition"}, + {0xe3, "DOS R/O or SpeedStor"}, + {0xe4, "SpeedStor 16-bit FAT extended partition < 1024 cyl."}, + {0xf1, "SpeedStor"}, + {0xf2, "DOS 3.3+ secondary"}, + {0xf4, "SpeedStor large partition"}, + {0xfe, "SpeedStor >1024 cyl. or LANstep"}, + {0xff, "Xenix Bad Block Table"} +}; + + +const char * +sysname(unsigned char type) { + struct systypes *s; + + for (s = sys_types; s - sys_types < SIZE(sys_types); s++) + if (s->type == type) + return s->name; + return "Unknown"; +} + +void +list_types(void) { + struct systypes *s; + + printf("Id Name\n\n"); + for (s = sys_types; s - sys_types < SIZE(sys_types); s++) + printf("%2x %s\n", s->type, s->name); +} + +int +is_extended(unsigned char type) { + return (type == EXTENDED_PARTITION || type == LINUX_EXTENDED); +} + +/* + * E. About partitions + */ + +/* MS/DOS partition */ + +struct partition { + unsigned char bootable; /* 0 or 0x80 */ + chs begin_chs; + unsigned char sys_type; + chs end_chs; + unsigned int start_sect; /* starting sector counting from 0 */ + unsigned int nr_sects; /* nr of sectors in partition */ +}; + +/* Unfortunately, partitions are not aligned, and non-Intel machines + are unhappy with non-aligned integers. So, we need a copy by hand. */ +int +copy_to_int(unsigned char *cp) { + unsigned int m; + + m = *cp++; + m += (*cp++ << 8); + m += (*cp++ << 16); + m += (*cp++ << 24); + return m; +} + +void +copy_from_int(int m, char *cp) { + *cp++ = (m & 0xff); m >>= 8; + *cp++ = (m & 0xff); m >>= 8; + *cp++ = (m & 0xff); m >>= 8; + *cp++ = (m & 0xff); +} + +void +copy_to_part(char *cp, struct partition *p) { + p->bootable = *cp++; + p->begin_chs.h = *cp++; + p->begin_chs.s = *cp++; + p->begin_chs.c = *cp++; + p->sys_type = *cp++; + p->end_chs.h = *cp++; + p->end_chs.s = *cp++; + p->end_chs.c = *cp++; + p->start_sect = copy_to_int(cp); + p->nr_sects = copy_to_int(cp+4); +} + +void +copy_from_part(struct partition *p, char *cp) { + *cp++ = p->bootable; + *cp++ = p->begin_chs.h; + *cp++ = p->begin_chs.s; + *cp++ = p->begin_chs.c; + *cp++ = p->sys_type; + *cp++ = p->end_chs.h; + *cp++ = p->end_chs.s; + *cp++ = p->end_chs.c; + copy_from_int(p->start_sect, cp); + copy_from_int(p->nr_sects, cp+4); +} + +/* Roughly speaking, Linux doesn't use any of the above fields except + for partition type, start sector and number of sectors. (However, + see also linux/drivers/scsi/fdomain.c.) + The only way partition type is used (in the kernel) is the comparison + for equality with EXTENDED_PARTITION (and these Disk Manager types). */ + +struct part_desc { + unsigned long start; + unsigned long size; + unsigned long sector, offset; /* disk location of this info */ + struct partition p; + struct part_desc *ep; /* extended partition containing this one */ +} zero_part_desc; + +struct part_desc * +outer_extended_partition(struct part_desc *p) { + while (p->ep) + p = p->ep; + return p; +} + +int +is_parent(struct part_desc *pp, struct part_desc *p) { + while (p) { + if (pp == p) + return 1; + p = p->ep; + } + return 0; +} + +struct disk_desc { + struct part_desc partitions[128]; + int partno; +} oldp, newp; + +/* determine where on the disk this information goes */ +void +add_sector_and_offset(struct disk_desc *z) { + int pno; + struct part_desc *p; + + for (pno = 0; pno < z->partno; pno++) { + p = &(z->partitions[pno]); + p->offset = 0x1be + (pno%4)*sizeof(struct partition); + p->sector = (p->ep ? p->ep->start : 0); + } +} + +/* tell the kernel to reread the partition tables */ +int reread_ioctl(int fd) { + if(ioctl(fd, BLKRRPART)) { + perror("BLKRRPART"); + return -1; + } + return 0; +} + +/* reread after writing */ +void +reread_disk_partition(char *dev, int fd) { + printf("Re-reading the partition table ...\n"); + fflush(stdout); + sync(); + sleep(3); /* superfluous since 1.3.20 */ + + if(reread_ioctl(fd)) + printf("The command to re-read the partition table failed\n" + "Reboot your system now, before using mkfs\n"); + + if (close(fd)) { + perror(dev); + printf("Error closing %s\n", dev); + } + printf("\n"); +} + +/* find Linux name of this partition, assuming that it will have a name */ +int +index_to_linux(int pno, struct disk_desc *z) { + int i, ct = 1; + struct part_desc *p = &(z->partitions[0]); + for (i=0; i<pno; i++,p++) + if(i < 4 || (p->size > 0 && !is_extended(p->p.sys_type))) + ct++; + return ct; +} + +int +linux_to_index(int lpno, struct disk_desc *z) { + int i, ct = 0; + struct part_desc *p = &(z->partitions[0]); + for (i=0; i<z->partno && ct < lpno; i++,p++) + if((i < 4 || (p->size > 0 && !is_extended(p->p.sys_type))) + && ++ct == lpno) + return i; + return -1; +} + +int +asc_to_index(char *pnam, struct disk_desc *z) { + int pnum, pno; + + if (*pnam == '#') { + pno = atoi(pnam+1); + } else { + pnum = atoi(pnam); + pno = linux_to_index(pnum, z); + } + if (!(pno >= 0 && pno < z->partno)) + fatal("%s: no such partition\n", pnam); + return pno; +} + +/* + * List partitions - in terms of sectors, blocks or cylinders + */ +#define F_SECTOR 1 +#define F_BLOCK 2 +#define F_CYLINDER 3 +#define F_MEGABYTE 4 + +int default_format = F_MEGABYTE; +int specified_format = 0; +int show_extended = 0; +int one_only = 0; +int one_only_pno; +int increment = 0; + +void +set_format(char c) { + switch(c) { + default: + printf("unrecognized format - using sectors\n"); + case 'S': specified_format = F_SECTOR; break; + case 'B': specified_format = F_BLOCK; break; + case 'C': specified_format = F_CYLINDER; break; + case 'M': specified_format = F_MEGABYTE; break; + } +} + +unsigned long +unitsize(int format) { + default_format = (cylindersize ? F_CYLINDER : F_MEGABYTE); + if (!format && !(format = specified_format)) + format = default_format; + + switch(format) { + default: + case F_CYLINDER: + if(cylindersize) return cylindersize; + case F_SECTOR: + return 1; + case F_BLOCK: + return 2; + case F_MEGABYTE: + return 2048; + } +} + +unsigned long +get_disksize(int format) { + unsigned long cs = cylinders; + if (cs && leave_last) + cs--; + return (cs * cylindersize) / unitsize(format); +} + +void +out_partition_header(char *dev, int format) { + if (dump) { + printf("# partition table of %s\n", dev); + printf("unit: sectors\n\n"); + return; + } + + default_format = (cylindersize ? F_CYLINDER : F_MEGABYTE); + if (!format && !(format = specified_format)) + format = default_format; + + switch(format) { + default: + printf("unimplemented format - using %s\n", + cylindersize ? "cylinders" : "sectors"); + case F_CYLINDER: + if (cylindersize) { + printf("Units = cylinders of %lu bytes, blocks of 1024 bytes" + ", counting from %d\n\n", + cylindersize<<9, increment); + printf(" Device Boot Start End #cyls #blocks Id System\n"); + break; + } + /* fall through */ + case F_SECTOR: + printf("Units = sectors of 512 bytes, counting from %d\n\n", + increment); + printf(" Device Boot Start End #sectors Id System\n"); + break; + case F_BLOCK: + printf("Units = blocks of 1024 bytes, counting from %d\n\n", + increment); + printf(" Device Boot Start End #blocks Id System\n"); + break; + case F_MEGABYTE: + printf("Units = megabytes of 1048576 bytes, blocks of 1024 bytes" + ", counting from %d\n\n", increment); + printf(" Device Boot Start End MB #blocks Id System\n"); + break; + } +} + +static void +out_rounddown(int width, unsigned long n, unsigned long unit, int inc) { + printf("%*lu", width, inc + n/unit); + if (unit != 1) + putchar((n % unit) ? '+' : ' '); + putchar(' '); +} + +static void +out_roundup(int width, unsigned long n, unsigned long unit, int inc) { + if (n == (unsigned long)(-1)) + printf("%*s", width, "-"); + else + printf("%*lu", width, inc + n/unit); + if (unit != 1) + putchar(((n+1) % unit) ? '-' : ' '); + putchar(' '); +} + +static void +out_roundup_size(int width, unsigned long n, unsigned long unit) { + printf("%*lu", width, (n+unit-1)/unit); + if (unit != 1) + putchar((n % unit) ? '-' : ' '); + putchar(' '); +} + +void +out_partition(char *dev, int format, struct part_desc *p, struct disk_desc *z) { + unsigned long start, end, size; + int pno, lpno; + + if (!format && !(format = specified_format)) + format = default_format; + + pno = p - &(z->partitions[0]); /* our index */ + lpno = index_to_linux(pno, z); /* name of next one that has a name */ + if(pno == linux_to_index(lpno, z)) /* was that us? */ + printf("%8s%-2u", dev, lpno); /* yes */ + else if(show_extended) + printf(" - "); + else + return; + putchar(dump ? ':' : ' '); + + start = p->start; + end = p->start + p->size - 1; + size = p->size; + + if (dump) { + printf(" start=%9lu", start); + printf(", size=%8lu", size); + printf(", Id=%2x", p->p.sys_type); + if (p->p.bootable == 0x80) + printf(", bootable"); + printf("\n"); + return; + } + + if(p->p.bootable == 0x80) + printf(" * "); + else if(p->p.bootable == 0) + printf(" "); + else + printf(" ? "); /* garbage */ + + switch(format) { + case F_CYLINDER: + if (cylindersize) { + out_rounddown(6, start, cylindersize, increment); + out_roundup(6, end, cylindersize, increment); + out_roundup_size(6, size, cylindersize); + out_rounddown(8, size, 2, 0); + break; + } + /* fall through */ + default: + case F_SECTOR: + out_rounddown(9, start, 1, increment); + out_roundup(9, end, 1, increment); + out_rounddown(9, size, 1, 0); + break; + case F_BLOCK: +#if 0 + printf("%8lu,%3lu ", + p->sector/2, ((p->sector & 1) ? 512 : 0) + p->offset); +#endif + out_rounddown(8, start, 2, increment); + out_roundup(8, end, 2, increment); + out_rounddown(8, size, 2, 0); + break; + case F_MEGABYTE: + out_rounddown(5, start, 2048, increment); + out_roundup(5, end, 2048, increment); + out_roundup_size(5, size, 2048); + out_rounddown(8, size, 2, 0); + break; + } + printf(" %2x %s\n", + p->p.sys_type, sysname(p->p.sys_type)); + + /* Is chs as we expect? */ + if (!quiet) { + chs a, b; + longchs aa, bb; + a = (size ? ulong_to_chs(start) : zero_chs); + b = p->p.begin_chs; + aa = chs_to_longchs(a); + bb = chs_to_longchs(b); + if(a.s && !is_equal_chs(a, b)) + printf("\t\tstart: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n", + aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); + a = (size ? ulong_to_chs(end) : zero_chs); + b = p->p.end_chs; + aa = chs_to_longchs(a); + bb = chs_to_longchs(b); + if(a.s && !is_equal_chs(a, b)) + printf("\t\tend: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n", + aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); + if(cylinders && cylinders < 1024 && bb.c > cylinders) + printf("partition ends on cylinder %ld, beyond the end of the disk\n", + bb.c); + } +} + +void +out_partitions(char *dev, struct disk_desc *z) { + int pno, format = 0; + + if (z->partno == 0) + printf("No partitions found\n"); + else { + out_partition_header(dev, format); + for(pno=0; pno < z->partno; pno++) { + out_partition(dev, format, &(z->partitions[pno]), z); + if(show_extended && pno%4==3) + printf("\n"); + } + } +} + +static int +disj(struct part_desc *p, struct part_desc *q) { + return + ((p->start + p->size <= q->start) + || (is_extended(p->p.sys_type) + && q->start + q->size <= p->start + p->size)); +} + +char * +pnumber(struct part_desc *p, struct disk_desc *z) { + static char buf[20]; + int this, next; + struct part_desc *p0 = &(z->partitions[0]); + + this = index_to_linux(p-p0, z); + next = index_to_linux(p-p0+1, z); + + if (next > this) + sprintf(buf, "%d", this); + else + sprintf(buf, "[%d]", this); + return buf; +} + +int +partitions_ok(struct disk_desc *z) { + struct part_desc *partitions = &(z->partitions[0]), *p, *q; + int partno = z->partno; + +#define PNO(p) pnumber(p, z) + + /* Have at least 4 partitions been defined? */ + if (partno < 4) { + if (!partno) + fatal("no partition table present.\n"); + else + fatal("strange, only %d partitions defined.\n", partno); + return 0; + } + + /* Are the partitions of size 0 marked empty? + And do they have start = 0? And bootable = 0? */ + for (p = partitions; p - partitions < partno; p++) + if (p->size == 0) { + if(p->p.sys_type != EMPTY_PARTITION) + warn("Warning: partition %s has size 0 but is not marked Empty\n", + PNO(p)); + else if(p->p.bootable != 0) + warn("Warning: partition %s has size 0 and is bootable\n", + PNO(p)); + else if(p->p.start_sect != 0) + warn("Warning: partition %s has size 0 and nonzero start\n", + PNO(p)); + /* all this is probably harmless, no error return */ + } + + /* Are the logical partitions contained in their extended partitions? */ + for (p = partitions+4; p < partitions+partno; p++) + if (p->size && !is_extended(p->p.sys_type)) { + q = p->ep; + if (p->start < q->start || p->start + p->size > q->start + q->size) { + warn("Warning: partition %s ", PNO(p)); + warn("is not contained in partition %s\n", PNO(q)); + return 0; + } + } + + /* Are the data partitions mutually disjoint? */ + for (p = partitions; p < partitions+partno; p++) + if (p->size && !is_extended(p->p.sys_type)) + for (q = p+1; q < partitions+partno; q++) + if (q->size && !is_extended(q->p.sys_type)) + if(!((p->start > q-> start) ? disj(q,p) : disj(p,q))) { + warn("Warning: partitions %s ", PNO(p)); + warn("and %s overlap\n", PNO(q)); + return 0; + } + + /* Do they start past zero and end before end-of-disk? */ + { unsigned long ds = get_disksize(F_SECTOR); + for (p = partitions; p < partitions+partno; p++) + if (p->size) { + if(p->start == 0) { + warn("Warning: partition %s starts at sector 0\n", PNO(p)); + return 0; + } + if (p->size && p->start + p->size > ds) { + warn("Warning: partition %s extends past end of disk\n", PNO(p)); + return 0; + } + } + } + + /* At most one chain of DOS extended partitions ? */ + /* It seems that the OS/2 fdisk has the additional requirement + that the extended partition must be the fourth one */ + { int ect = 0; + for (p = partitions; p < partitions+4; p++) + if (p->p.sys_type == EXTENDED_PARTITION) + ect++; + if (ect > 1 && !Linux) { + warn("Among the primary partitions, at most one can be extended\n"); + warn(" (although this is not a problem under Linux)\n"); + return 0; + } + } + + /* + * Do all partitions start at a cylinder boundary ? + * (this is not required for Linux) + * The first partition starts after MBR. + * Logical partitions start slightly after the containing extended partn. + */ + if (cylindersize) { + for(p = partitions; p < partitions+partno; p++) + if (p->size) { + if(p->start % cylindersize != 0 + && (!p->ep || p->start / cylindersize != p->ep->start / cylindersize) + && (p->p.start_sect >= cylindersize)) { + warn("Warning: partition %s does not start " + "at a cylinder boundary\n", PNO(p)); + if (!Linux) + return 0; + } + if((p->start + p->size) % cylindersize) { + warn("Warning: partition %s does not end " + "at a cylinder boundary\n", PNO(p)); + if (!Linux) + return 0; + } + } + } + + /* Usually, one can boot only from primary partitions. */ + /* In fact, from a unique one only. */ + /* do not warn about bootable extended partitions - + often LILO is there */ + { int pno = -1; + for(p = partitions; p < partitions+partno; p++) + if (p->p.bootable) { + if (pno == -1) + pno = p - partitions; + else if (p - partitions < 4) { + warn("Warning: more than one primary partition is marked " + "bootable (active)\n" + "This does not matter for LILO, but the DOS MBR will " + "not boot this disk.\n"); + break; + } + if (p - partitions >= 4) { + warn("Warning: usually one can boot from primary partitions " + "only\n" "LILO disregards the `bootable' flag.\n"); + break; + } + } + if (pno == -1 || pno >= 4) + warn("Warning: no primary partition is marked bootable (active)\n" + "This does not matter for LILO, but the DOS MBR will " + "not boot this disk.\n"); + } + + /* Is chs as we expect? */ + for(p = partitions; p < partitions+partno; p++) { + chs a, b; + longchs aa, bb; + a = p->size ? ulong_to_chs(p->start) : zero_chs; + b = p->p.begin_chs; + aa = chs_to_longchs(a); + bb = chs_to_longchs(b); + if (!chs_ok(b, PNO(p), "start")) + return 0; + if(a.s && !is_equal_chs(a, b)) + warn("partition %s: start: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n", + PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); + a = p->size ? ulong_to_chs(p->start + p->size - 1) : zero_chs; + b = p->p.end_chs; + aa = chs_to_longchs(a); + bb = chs_to_longchs(b); + if (!chs_ok(b, PNO(p), "end")) + return 0; + if(a.s && !is_equal_chs(a, b)) + warn("partition %s: end: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n", + PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); + if(cylinders && cylinders < 1024 && bb.c > cylinders) + warn("partition %s ends on cylinder %ld, beyond the end of the disk\n", + PNO(p), bb.c); + } + + return 1; + +#undef PNO +} + +static void +extended_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) { + char *cp; + struct sector *s; + unsigned long start, here, next; + int i, moretodo = 1; + struct partition p; + struct part_desc *partitions = &(z->partitions[0]); + int pno = z->partno; + + here = start = ep->start; + + while (moretodo) { + moretodo = 0; + + if (!(s = get_sector(dev, fd, here))) + break; + + if (!msdos_signature(s)) + break; + + cp = s->data + 0x1be; + + if (pno+4 >= SIZE(z->partitions)) { + printf("too many partitions - ignoring those past nr (%d)\n", + pno-1); + break; + } + + next = 0; + + for (i=0; i<4; i++,cp += sizeof(struct partition)) { + partitions[pno].sector = here; + partitions[pno].offset = cp - s->data; + partitions[pno].ep = ep; + copy_to_part(cp,&p); + if (is_extended(p.sys_type)) { + if (next) + printf("tree of partitions?\n"); + partitions[pno].start = next = start + p.start_sect; + moretodo = 1; + } else { + partitions[pno].start = here + p.start_sect; + } + partitions[pno].size = p.nr_sects; + partitions[pno++].p = p; + } + here = next; + } + + z->partno = pno; +} + +static int +msdos_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { + int i; + char *cp; + struct partition pt; + struct sector *s; + struct part_desc *partitions = &(z->partitions[0]); + int pno = z->partno; + + if (!(s = get_sector(dev, fd, start))) + return 0; + + if (!msdos_signature(s)) + return 0; + + cp = s->data + 0x1be; + copy_to_part(cp,&pt); + + /* If I am not mistaken, recent kernels will hide this from us, + so we will never actually see traces of a Disk Manager */ + if (pt.sys_type == DM6_PARTITION + || pt.sys_type == EZD_PARTITION + || pt.sys_type == DM6_AUX1PARTITION + || pt.sys_type == DM6_AUX3PARTITION) { + printf("detected Disk Manager - unable to handle that\n"); + return 0; + } + { unsigned int sig = *(unsigned short *)(s->data + 2); + if (sig <= 0x1ae + && *(unsigned short *)(s->data + sig) == 0x55aa + && (1 & *(unsigned char *)(s->data + sig + 2))) { + printf("DM6 signature found - giving up\n"); + return 0; + } + } + + for (pno=0; pno<4; pno++,cp += sizeof(struct partition)) { + partitions[pno].sector = start; + partitions[pno].offset = cp - s->data; + copy_to_part(cp,&pt); + partitions[pno].start = start + pt.start_sect; + partitions[pno].size = pt.nr_sects; + partitions[pno].ep = 0; + partitions[pno].p = pt; + } + + z->partno = pno; + + for (i=0; i<4; i++) + if (is_extended(partitions[i].p.sys_type)) { + if (!partitions[i].size) { + printf("strange..., an extended partition of size 0?\n"); + continue; + } + extended_partition(dev, fd, &partitions[i], z); + } + + return 1; +} + +static int +osf_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { + return 0; +} + +void +get_partitions(char *dev, int fd, struct disk_desc *z) { + z->partno = 0; + + if (!msdos_partition(dev, fd, 0, z) && !osf_partition(dev, fd, 0, z)) { + printf(" %s: unrecognized partition\n", dev); + return; + } +} + +int +write_partitions(char *dev, int fd, struct disk_desc *z) { + struct sector *s; + struct part_desc *partitions = &(z->partitions[0]), *p; + int pno = z->partno; + + if (no_write) { + printf("-n flag was given: Nothing changed\n"); + exit(0); + } + + for (p = partitions; p < partitions+pno; p++) { + s = get_sector(dev, fd, p->sector); + if (!s) return 0; + s->to_be_written = 1; + copy_from_part(&(p->p), s->data + p->offset); + *(unsigned short *)(&(s->data[0x1fe])) = 0xaa55; + } + if (save_sector_file) { + if (!save_sectors(dev, fd)) { + fatal("Failed saving the old sectors - aborting\n"); + return 0; + } + } + if (!write_sectors(dev, fd)) { + error("Failed writing the partition on %s\n", dev); + return 0; + } + return 1; +} + +/* + * F. The standard input + */ + +/* + * Input format: + * <start> <size> <type> <bootable> <c,h,s> <c,h,s> + * Fields are separated by whitespace or comma or semicolon possibly + * followed by whitespace; initial and trailing whitespace is ignored. + * Numbers can be octal, decimal or hexadecimal, decimal is default + * The <c,h,s> parts can (and probably should) be omitted. + * Bootable is specified as [*|-], with as default not-bootable. + * Type is given in hex, without the 0x prefix, or is [E|S|L|X], where + * L (LINUX_NATIVE (83)) is the default, S is LINUX_SWAP (82), and E + * is EXTENDED_PARTITION (5), X is LINUX_EXTENDED (85). + * The default value of start is the first nonassigned sector/cylinder/... + * The default value of size is as much as possible (until next + * partition or end-of-disk). + * .: end of chain of extended partitions. + * + * On interactive input an empty line means: all defaults. + * Otherwise empty lines are ignored. + */ + +int eof, eob; + +struct dumpfld { + int fldno; + char *fldname; + int is_bool; +} dumpflds[] = { + { 0, "start", 0 }, + { 1, "size", 0 }, + { 2, "Id", 0 }, + { 3, "bootable", 1 }, + { 4, "bh", 0 }, + { 5, "bs", 0 }, + { 6, "bc", 0 }, + { 7, "eh", 0 }, + { 8, "es", 0 }, + { 9, "ec", 0 } +}; + +/* + * Read a line, split it into fields + * + * (some primitive handwork, but a more elaborate parser seems + * unnecessary) + */ +#define RD_EOF (-1) +#define RD_CMD (-2) + +int +read_stdin(unsigned char **fields, unsigned char *line, int fieldssize, int linesize) { + unsigned char *lp, *ip; + int c, fno; + + /* boolean true and empty string at start */ + line[0] = '*'; + line[1] = 0; + for (fno=0; fno < fieldssize; fno++) + fields[fno] = line + 1; + fno = 0; + + /* read a line from stdin */ + lp = fgets(line+2, linesize, stdin); + if (lp == NULL) { + eof = 1; + return RD_EOF; + } + if (!(lp = index(lp, '\n'))) + fatal("long or incomplete input line - quitting\n"); + *lp = 0; + + /* remove comments, if any */ + if ((lp = index(line+2, '#')) != 0) + *lp = 0; + + /* recognize a few commands - to be expanded */ + if (!strcmp(line+2, "unit: sectors")) { + specified_format = F_SECTOR; + return RD_CMD; + } + + /* dump style? - then bad input is fatal */ + if ((ip = index(line+2, ':')) != 0) { + struct dumpfld *d; + + nxtfld: + ip++; + while(isspace(*ip)) + ip++; + if (*ip == 0) + return fno; + for(d = dumpflds; d-dumpflds < SIZE(dumpflds); d++) { + if(!strncmp(ip, d->fldname, strlen(d->fldname))) { + ip += strlen(d->fldname); + while(isspace(*ip)) + ip++; + if (d->is_bool) + fields[d->fldno] = line; + else if (*ip == '=') { + while(isspace(*++ip)) ; + fields[d->fldno] = ip; + while(isalnum(*ip)) /* 0x07FF */ + ip++; + } else + fatal("input error: `=' expected after %s field\n", + d->fldname); + if (fno <= d->fldno) + fno = d->fldno + 1; + if(*ip == 0) + return fno; + if(*ip != ',' && *ip != ';') + fatal("input error: unexpected character %c after %s field\n", + *ip, d->fldname); + *ip = 0; + goto nxtfld; + } + } + fatal("unrecognized input: %s\n", ip); + } + + /* split line into fields */ + lp = ip = line+2; + fields[fno++] = lp; + while((c = *ip++) != 0) { + if (!lp[-1] && (c == '\t' || c == ' ')) + ; + else if (c == '\t' || c == ' ' || c == ',' || c == ';') { + *lp++ = 0; + if (fno < fieldssize) + fields[fno++] = lp; + continue; + } else + *lp++ = c; + } + + if (lp == fields[fno-1]) + fno--; + return fno; +} + +/* read a number, use default if absent */ +int +get_ul(char *u, unsigned long *up, unsigned long def, int base) { + char *nu; + + if (*u) { + errno = 0; + *up = strtoul(u, &nu, base); + if (errno == ERANGE) { + printf("number too big\n"); + return -1; + } + if (*nu) { + printf("trailing junk after number\n"); + return -1; + } + } else + *up = def; + return 0; +} + +/* There are two common ways to structure extended partitions: + as nested boxes, and as a chain. Sometimes the partitions + must be given in order. Sometimes all logical partitions + must lie inside the outermost extended partition. +NESTED: every partition is contained in the surrounding partitions + and is disjoint from all others. +CHAINED: every data partition is contained in the surrounding partitions + and disjoint from all others, but extended partitions may lie outside + (insofar as allowed by all_logicals_inside_outermost_extended). +ONESECTOR: all data partitions are mutually disjoint; extended partitions + each use one sector only (except perhaps for the outermost one). +*/ +int partitions_in_order = 0; +int all_logicals_inside_outermost_extended = 1; +enum { NESTED, CHAINED, ONESECTOR } boxes = NESTED; + +/* find the default value for <start> - assuming entire units */ +unsigned long +first_free(int pno, int is_extended, struct part_desc *ep, int format, + unsigned long mid, struct disk_desc *z) { + unsigned long ff, fff; + unsigned long unit = unitsize(format); + struct part_desc *partitions = &(z->partitions[0]), *pp = 0; + + /* if containing ep undefined, look at its container */ + if (ep && ep->p.sys_type == EMPTY_PARTITION) + ep = ep->ep; + + if (ep) { + if (boxes == NESTED || (boxes == CHAINED && !is_extended)) + pp = ep; + else if (all_logicals_inside_outermost_extended) + pp = outer_extended_partition(ep); + } +#if 0 + ff = pp ? (pp->start + unit - 1) / unit : 0; +#else + /* rounding up wastes almost an entire cylinder - round down + and leave it to compute_start_sect() to fix the difference */ + ff = pp ? pp->start / unit : 0; +#endif + /* MBR and 1st sector of an extended partition are never free */ + if (unit == 1) + ff++; + + again: + for(pp = partitions; pp < partitions+pno; pp++) { + if (!is_parent(pp, ep) && pp->size > 0) { + if ((partitions_in_order || pp->start / unit <= ff + || (mid && pp->start / unit <= mid)) + && (fff = (pp->start + pp->size + unit - 1) / unit) > ff) { + ff = fff; + goto again; + } + } + } + + return ff; +} + +/* find the default value for <size> - assuming entire units */ +unsigned long +max_length(int pno, int is_extended, struct part_desc *ep, int format, + unsigned long start, struct disk_desc *z) { + unsigned long fu; + unsigned long unit = unitsize(format); + struct part_desc *partitions = &(z->partitions[0]), *pp = 0; + + /* if containing ep undefined, look at its container */ + if (ep && ep->p.sys_type == EMPTY_PARTITION) + ep = ep->ep; + + if (ep) { + if (boxes == NESTED || (boxes == CHAINED && !is_extended)) + pp = ep; + else if (all_logicals_inside_outermost_extended) + pp = outer_extended_partition(ep); + } + fu = pp ? (pp->start + pp->size) / unit : get_disksize(format); + + for(pp = partitions; pp < partitions+pno; pp++) + if (!is_parent(pp, ep) && pp->size > 0 + && pp->start / unit >= start && pp->start / unit < fu) + fu = pp->start / unit; + + return (fu > start) ? fu - start : 0; +} + +/* compute starting sector of a partition inside an extended one */ +/* ep is 0 or points to surrounding extended partition */ +int +compute_start_sect(struct part_desc *p, struct part_desc *ep) { + unsigned long base; + int inc = (DOS && sectors) ? sectors : 1; + int delta; + + if (ep && p->start + p->size >= ep->start + 1) + delta = p->start - ep->start - inc; + else if (p->start == 0 && p->size > 0) + delta = -inc; + else + delta = 0; + if (delta < 0) { + p->start -= delta; + p->size += delta; + if (is_extended(p->p.sys_type) && boxes == ONESECTOR) + p->size = inc; + else if ((int)(p->size) <= 0) { + warn("no room for partition descriptor\n"); + return 0; + } + } + base = (!ep ? 0 + : (is_extended(p->p.sys_type) ? + outer_extended_partition(ep) : ep)->start); + p->ep = ep; + if (p->p.sys_type == EMPTY_PARTITION && p->size == 0) { + p->p.start_sect = 0; + p->p.begin_chs = zero_chs; + p->p.end_chs = zero_chs; + } else { + p->p.start_sect = p->start - base; + p->p.begin_chs = ulong_to_chs(p->start); + p->p.end_chs = ulong_to_chs(p->start + p->size - 1); + } + p->p.nr_sects = p->size; + return 1; +} + +/* build the extended partition surrounding a given logical partition */ +int +build_surrounding_extended(struct part_desc *p, struct part_desc *ep, + struct disk_desc *z) { + int inc = (DOS && sectors) ? sectors : 1; + int format = F_SECTOR; + struct part_desc *p0 = &(z->partitions[0]), *eep = ep->ep; + + if (boxes == NESTED) { + ep->start = first_free(ep-p0, 1, eep, format, p->start, z); + ep->size = max_length(ep-p0, 1, eep, format, ep->start, z); + if (ep->start > p->start || ep->start + ep->size < p->start + p->size) { + warn("cannot build surrounding extended partition\n"); + return 0; + } + } else { + ep->start = p->start; + if(boxes == CHAINED) + ep->size = p->size; + else + ep->size = inc; + } + + ep->p.nr_sects = ep->size; + ep->p.bootable = 0; + ep->p.sys_type = EXTENDED_PARTITION; + if (!compute_start_sect(ep, eep) || !compute_start_sect(p, ep)) { + ep->p.sys_type = EMPTY_PARTITION; + ep->size = 0; + return 0; + } + + return 1; +} + +int +read_line(int pno, struct part_desc *ep, char *dev, int interactive, + struct disk_desc *z) { + unsigned char line[1000]; + unsigned char *fields[11]; + int fno, pct = pno%4; + struct part_desc p, *orig; + unsigned long ff, ff1, ul, ml, ml1, def; + int format, lpno, is_extd; + + if (eof || eob) + return -1; + + lpno = index_to_linux(pno, z); + + if (interactive) { + if (pct == 0 && (show_extended || pno == 0)) + warn("\n"); + warn("%8s%d: ", dev, lpno); + } + + /* read input line - skip blank lines when reading from a file */ + do { + fno = read_stdin(fields, line, SIZE(fields), SIZE(line)); + } while(fno == RD_CMD || (fno == 0 && !interactive)); + if (fno == RD_EOF) { + return -1; + } else if (fno > 10 && *(fields[10]) != 0) { + printf("too many input fields\n"); + return 0; + } + + if (fno == 1 && !strcmp(fields[0], ".")) { + eob = 1; + return -1; + } + + /* use specified format, but round to cylinders if F_MEGABYTE specified */ + format = 0; + if (cylindersize && specified_format == F_MEGABYTE) + format = F_CYLINDER; + + orig = (one_only ? &(oldp.partitions[pno]) : 0); + + p = zero_part_desc; + p.ep = ep; + + /* first read the type - we need to know whether it is extended */ + /* stop reading when input blank (defaults) and all is full */ + is_extd = 0; + if (fno == 0) { /* empty line */ + if (orig && is_extended(orig->p.sys_type)) + is_extd = 1; + ff = first_free(pno, is_extd, ep, format, 0, z); + ml = max_length(pno, is_extd, ep, format, ff, z); + if (ml == 0 && is_extd == 0) { + is_extd = 1; + ff = first_free(pno, is_extd, ep, format, 0, z); + ml = max_length(pno, is_extd, ep, format, ff, z); + } + if (ml == 0 && pno >= 4) { + /* no free blocks left - don't read any further */ + warn("No room for more\n"); + return -1; + } + } + if (fno < 3 || !*(fields[2])) + ul = orig ? orig->p.sys_type : + (is_extd || (pno > 3 && pct == 1 && show_extended)) + ? EXTENDED_PARTITION : LINUX_NATIVE; + else if(!strcmp(fields[2], "L")) + ul = LINUX_NATIVE; + else if(!strcmp(fields[2], "S")) + ul = LINUX_SWAP; + else if(!strcmp(fields[2], "E")) + ul = EXTENDED_PARTITION; + else if(!strcmp(fields[2], "X")) + ul = LINUX_EXTENDED; + else if (get_ul(fields[2], &ul, LINUX_NATIVE, 16)) + return 0; + if (ul > 255) { + warn("Illegal type\n"); + return 0; + } + p.p.sys_type = ul; + is_extd = is_extended(ul); + + /* find start */ + ff = first_free(pno, is_extd, ep, format, 0, z); + ff1 = ff * unitsize(format); + def = orig ? orig->start : (pno > 4 && pct > 1) ? 0 : ff1; + if (fno < 1 || !*(fields[0])) + p.start = def; + else { + if (get_ul(fields[0], &ul, def / unitsize(0), 0)) + return 0; + p.start = ul * unitsize(0); + p.start -= (p.start % unitsize(format)); + } + + /* find length */ + ml = max_length(pno, is_extd, ep, format, p.start / unitsize(format), z); + ml1 = ml * unitsize(format); + def = orig ? orig->size : (pno > 4 && pct > 1) ? 0 : ml1; + if (fno < 2 || !*(fields[1])) + p.size = def; + else { + if (get_ul(fields[1], &ul, def / unitsize(0), 0)) + return 0; + p.size = ul * unitsize(0) + unitsize(format) - 1; + p.size -= (p.size % unitsize(format)); + } + if (p.size > ml1) { + warn("Warning: exceeds max allowable size (%lu)\n", ml1 / unitsize(0)); + if (!force) + return 0; + } + if (p.size == 0 && pno >= 4 && (fno < 2 || !*(fields[1]))) { + warn("Warning: empty partition\n"); + if (!force) + return 0; + } + p.p.nr_sects = p.size; + + if (p.size == 0 && !orig) { + if(fno < 1 || !*(fields[0])) + p.start = 0; + if(fno < 3 || !*(fields[2])) + p.p.sys_type = EMPTY_PARTITION; + } + + if (p.start < ff1 && p.size > 0) { + warn("Warning: bad partition start (earliest %lu)\n", + (ff1 + unitsize(0) - 1) / unitsize(0)); + if (!force) + return 0; + } + + if (fno < 4 || !*(fields[3])) + ul = (orig ? orig->p.bootable : 0); + else if (!strcmp(fields[3], "-")) + ul = 0; + else if (!strcmp(fields[3], "*") || !strcmp(fields[3], "+")) + ul = 0x80; + else { + warn("unrecognized bootable flag - choose - or *\n"); + return 0; + } + p.p.bootable = ul; + + if (ep && ep->p.sys_type == EMPTY_PARTITION) { + if(!build_surrounding_extended(&p, ep, z)) + return 0; + } else + if(!compute_start_sect(&p, ep)) + return 0; + + { longchs aa = chs_to_longchs(p.p.begin_chs), bb; + + if (fno < 5) { + bb = aa; + } else if (fno < 7) { + warn("partial c,h,s specification?\n"); + return 0; + } else if(get_ul(fields[4], &bb.c, aa.c, 0) || + get_ul(fields[5], &bb.h, aa.h, 0) || + get_ul(fields[6], &bb.s, aa.s, 0)) + return 0; + p.p.begin_chs = longchs_to_chs(bb); + } + { longchs aa = chs_to_longchs(p.p.end_chs), bb; + + if (fno < 8) { + bb = aa; + } else if (fno < 10) { + warn("partial c,h,s specification?\n"); + return 0; + } else if(get_ul(fields[7], &bb.c, aa.c, 0) || + get_ul(fields[8], &bb.h, aa.h, 0) || + get_ul(fields[9], &bb.s, aa.s, 0)) + return 0; + p.p.end_chs = longchs_to_chs(bb); + } + + if (pno > 3 && p.size && show_extended && p.p.sys_type != EMPTY_PARTITION + && (is_extended(p.p.sys_type) != (pct == 1))) { + warn("Extended partition not where expected\n"); + if (!force) + return 0; + } + + z->partitions[pno] = p; + if (pno >= z->partno) + z->partno += 4; /* reqd for out_partition() */ + + if (interactive) + out_partition(dev, 0, &(z->partitions[pno]), z); + + return 1; +} + +/* ep either points to the extended partition to contain this one, + or to the empty partition that may become extended or is 0 */ +int +read_partition(char *dev, int interactive, int pno, struct part_desc *ep, + struct disk_desc *z) { + struct part_desc *p = &(z->partitions[pno]); + int i; + + if (one_only) { + *p = oldp.partitions[pno]; + if (one_only_pno != pno) + goto ret; + } else if (!show_extended && pno > 4 && pno%4) + goto ret; + + while (!(i = read_line(pno, ep, dev, interactive, z))) + if (!interactive) + fatal("bad input\n"); + if (i < 0) { + p->ep = ep; + return 0; + } + + ret: + p->ep = ep; + if (pno >= z->partno) + z->partno += 4; + return 1; +} + +void +read_partition_chain(char *dev, int interactive, struct part_desc *ep, + struct disk_desc *z) { + int i, base; + + eob = 0; + while (1) { + base = z->partno; + if (base+4 > SIZE(z->partitions)) { + printf("too many partitions\n"); + break; + } + for (i=0; i<4; i++) + if (!read_partition(dev, interactive, base+i, ep, z)) + return; + for (i=0; i<4; i++) { + ep = &(z->partitions[base+i]); + if (is_extended(ep->p.sys_type) && ep->size) + break; + } + if (i == 4) { + /* nothing found - maybe an empty partition is going + to be extended */ + if (one_only || show_extended) + break; + ep = &(z->partitions[base+1]); + if (ep->size || ep->p.sys_type != EMPTY_PARTITION) + break; + } + } +} + +void +read_input(char *dev, int interactive, struct disk_desc *z) { + int i; + struct part_desc *partitions = &(z->partitions[0]), *ep; + + for (i=0; i < SIZE(z->partitions); i++) + partitions[i] = zero_part_desc; + z->partno = 0; + + if (interactive) + warn(" +Input in the following format; absent fields get a default value. +<start> <size> <type [E,S,L,X,hex]> <bootable [-,*]> <c,h,s> <c,h,s> +Usually you only need to specify <start> and <size> (and perhaps <type>). +"); + eof = 0; + + for (i=0; i<4; i++) + read_partition(dev, interactive, i, 0, z); + for (i=0; i<4; i++) { + ep = partitions+i; + if (is_extended(ep->p.sys_type) && ep->size) + read_partition_chain(dev, interactive, ep, z); + } + add_sector_and_offset(z); +} + +/* + * G. The command line + */ + +static void version(void) { + printf(PROGNAME " version " VERSION " (aeb@cwi.nl, " DATE ")\n"); +} + +static void +usage(void) { + version(); + printf("Usage: + " PROGNAME " [options] device ... +device: something like /dev/hda or /dev/sda +useful options: + -s [or --show-size]: list size of a partition + -c [or --id]: print or change partition Id + -l [or --list]: list partitions of each device + -d [or --dump]: idem, but in a format suitable for later input + -i [or --increment]: number cylinders etc. from 1 instead of from 0 + -uS, -uB, -uC, -uM: accept/report in units of sectors/blocks/cylinders/MB + -T [or --list-types]:list the known partition types + -D [or --DOS]: for DOS-compatibility: waste a little space + -R [or --re-read]: make kernel reread partition table + -N# : change only the partition with number # + -n : do not actually write to disk + -O file : save the sectors that will be overwritten to file + -I file : restore these sectors again + -v [or --version]: print version + -? [or --help]: print this message +dangerous options: + -g [or --show-geometry]: print the kernel's idea of the geometry + -x [or --show-extended]: also list extended partitions on output + or expect descriptors for them on input + -L [or --Linux]: do not complain about things irrelevant for Linux + -q [or --quiet]: suppress warning messages + You can override the detected geometry using: + -C# [or --cylinders #]:set the number of cylinders to use + -H# [or --heads #]: set the number of heads to use + -S# [or --sectors #]: set the number of sectors to use + You can disable all consistency checking with: + -f [or --force]: do what I say, even if it is stupid +"); + exit(1); +} + +static void +activate_usage(char *progn) { + printf("Usage: + %s device list active partitions on device + %s device n1 n2 ... activate partitions n1 ..., inactivate the rest + %s device activate partition n, inactivate the other ones +", progn, progn, PROGNAME " -An"); + exit(1); +} + +static void +unhide_usage(char *progn) { + exit(1); +} + +static char short_opts[] = "cdfgilnqsu:vx?1A::C:DH:I:LN:O:RS:TU::V"; + +#define PRINT_ID 0400 +#define CHANGE_ID 01000 + +static const struct option long_opts[] = { + { "change-id", no_argument, NULL, 'c' + CHANGE_ID }, + { "print-id", no_argument, NULL, 'c' + PRINT_ID }, + { "id", no_argument, NULL, 'c' }, + { "dump", no_argument, NULL, 'd' }, + { "force", no_argument, NULL, 'f' }, + { "show-geometry", no_argument, NULL, 'g' }, + { "increment", no_argument, NULL, 'i' }, + { "list", no_argument, NULL, 'l' }, + { "quiet", no_argument, NULL, 'q' }, + { "show-size", no_argument, NULL, 's' }, + { "unit", required_argument, NULL, 'u' }, + { "version", no_argument, NULL, 'v' }, + { "show-extended", no_argument, NULL, 'x' }, + { "help", no_argument, NULL, '?' }, + { "one-only", no_argument, NULL, '1' }, + { "cylinders", required_argument, NULL, 'C' }, + { "heads", required_argument, NULL, 'H' }, + { "sectors", required_argument, NULL, 'S' }, + { "activate", optional_argument, NULL, 'A' }, + { "DOS", no_argument, NULL, 'D' }, + { "Linux", no_argument, NULL, 'L' }, + { "re-read", no_argument, NULL, 'R' }, + { "list-types", no_argument, NULL, 'T' }, + { "unhide", optional_argument, NULL, 'U' }, + { "no-reread", no_argument, NULL, 160 }, + { "IBM", no_argument, NULL, 161 }, + { "leave-last", no_argument, NULL, 161 }, +/* undocumented flags - not all completely implemented */ + { "in-order", no_argument, NULL, 128 }, + { "not-in-order", no_argument, NULL, 129 }, + { "inside-outer", no_argument, NULL, 130 }, + { "not-inside-outer", no_argument, NULL, 131 }, + { "nested", no_argument, NULL, 132 }, + { "chained", no_argument, NULL, 133 }, + { "onesector", no_argument, NULL, 134 }, + { NULL, 0, NULL, 0 } +}; + +/* default devices to list */ +static struct devd { + char *pref, *letters; +} defdevs[] = { + { "hd", "abcdefgh" }, + { "sd", "abcde" }, + { "xd", "ab" } +}; + +void do_list(char *dev, int silent); +void do_size(char *dev, int silent); +void do_geom(char *dev, int silent); +void do_fdisk(char *dev); +void do_reread(char *dev); +void do_change_id(char *dev, char *part, char *id); +void do_unhide(char **av, int ac, char *arg); +void do_activate(char **av, int ac, char *arg); + +int total_size; + +int +main(int argc, char **argv) { + char *progn; + int c; + char *dev; + int opt_size = 0; + int opt_out_geom = 0; + int opt_reread = 0; + int activate = 0; + int do_id = 0; + int unhide = 0; + int fdisk = 0; + char *activatearg = 0; + char *unhidearg = 0; + + if (argc < 1) + fatal("no command?\n"); + if ((progn = rindex(argv[0], '/')) == NULL) + progn = argv[0]; + else + progn++; + if (!strcmp(progn, "activate")) + activate = 1; /* equivalent to `fdisk -A' */ +#if 0 /* not important enough to deserve a name */ + else if (!strcmp(progn, "unhide")) + unhide = 1; /* equivalent to `fdisk -U' */ +#endif + else + fdisk = 1; + + while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL)) != -1) { + switch (c) { + case 'f': + force = 1; break; /* does not imply quiet */ + case 'g': + opt_out_geom = 1; break; + case 'i': + increment = 1; break; + case 'c': + case 'c' + PRINT_ID: + case 'c' + CHANGE_ID: + do_id = c; break; + case 'd': + dump = 1; /* fall through */ + case 'l': + opt_list = 1; break; + case 'n': + no_write = 1; break; + case 'q': + quiet = 1; break; + case 's': + opt_size = 1; break; + case 'u': + set_format(*optarg); break; + case 'v': + version(); + exit(0); + case 'x': + show_extended = 1; break; + case 'A': + activatearg = optarg; + activate = 1; break; + case 'C': + specified_cylinders = atoi(optarg); break; + case 'D': + DOS = 1; break; + case 'H': + specified_heads = atoi(optarg); break; + case 'L': + Linux = 1; break; + case 'N': + one_only = atoi(optarg); break; + case 'I': + restore_sector_file = optarg; break; + case 'O': + save_sector_file = optarg; break; + case 'R': + opt_reread = 1; break; + case 'S': + specified_sectors = atoi(optarg); break; + case 'T': + list_types(); + exit(0); + case 'U': + unhidearg = optarg; + unhide = 1; break; + case 'V': + verify = 1; break; + case '?': + default: + usage(); break; + + /* undocumented flags */ + case 128: + partitions_in_order = 1; break; + case 129: + partitions_in_order = 0; break; + case 130: + all_logicals_inside_outermost_extended = 1; break; + case 131: + all_logicals_inside_outermost_extended = 0; break; + case 132: + boxes = NESTED; break; + case 133: + boxes = CHAINED; break; + case 134: + boxes = ONESECTOR; break; + + /* more flags */ + case 160: + no_reread = 1; break; + case 161: + leave_last = 1; break; + } + } + + if (optind == argc && (opt_list || opt_out_geom || opt_size || verify)) { + struct devd *dp; + char *lp; + char device[10]; + + total_size = 0; + + for(dp = defdevs; dp-defdevs < SIZE(defdevs); dp++) { + lp = dp->letters; + while(*lp) { + sprintf(device, "/dev/%s%c", dp->pref, *lp++); + if (opt_out_geom) + do_geom(device, 1); + if (opt_size) + do_size(device, 1); + if (opt_list || verify) + do_list(device, 1); + } + } + + if (opt_size) + printf("total: %d blocks\n", total_size); + + exit(exit_status); + } + + if (optind == argc) { + if (activate) + activate_usage(fdisk ? "fdisk -A" : progn); + else if (unhide) + unhide_usage(fdisk ? "fdisk -U" : progn); + else + usage(); + } + + if (opt_list || opt_out_geom || opt_size || verify) { + while (optind < argc) { + if (opt_out_geom) + do_geom(argv[optind], 0); + if (opt_size) + do_size(argv[optind], 0); + if (opt_list || verify) + do_list(argv[optind], 0); + optind++; + } + exit(exit_status); + } + + if (activate) { + do_activate(argv+optind, argc-optind, activatearg); + exit(exit_status); + } + if (unhide) { + do_unhide(argv+optind, argc-optind, unhidearg); + exit(exit_status); + } + if (do_id) { + if ((do_id & PRINT_ID) != 0 && optind != argc-2) + fatal("usage: fdisk --print-id device partition-number\n"); + else if ((do_id & CHANGE_ID) != 0 && optind != argc-3) + fatal("usage: fdisk --change-id device partition-number Id\n"); + else if (optind != argc-3 && optind != argc-2) + fatal("usage: fdisk --id device partition-number [Id]\n"); + do_change_id(argv[optind], argv[optind+1], + (optind == argc-2) ? 0 : argv[optind+2]); + exit(exit_status); + } + + if (optind != argc-1) + fatal("can specify only one device (except with -l or -s)\n"); + dev = argv[optind]; + + if (opt_reread) + do_reread(dev); + else if (restore_sector_file) + restore_sectors(dev); + else + do_fdisk(dev); + + return 0; +} + +/* + * H. Listing the current situation + */ + +int +my_open (char *dev, int rw, int silent) { + int fd, mode; + + mode = (rw ? O_RDWR : O_RDONLY); + fd = open(dev, mode); + if (fd < 0 && !silent) { + perror(dev); + fatal("cannot open %s %s\n", dev, rw ? "read-write" : "for reading"); + } + return fd; +} + +void +do_list (char *dev, int silent) { + int fd; + struct disk_desc *z; + + fd = my_open(dev, 0, silent); + if (fd < 0) + return; + + z = &oldp; + + free_sectors(); + get_cylindersize(dev, fd, dump ? 1 : opt_list ? 0 : 1); + get_partitions(dev, fd, z); + + if (opt_list) + out_partitions(dev, z); + + if (verify) { + if (partitions_ok(z)) + warn("%s: OK\n", dev); + else + exit_status = 1; + } +} + +void +do_geom (char *dev, int silent) { + int fd; + struct hd_geometry g; + + fd = my_open(dev, 0, silent); + if (fd < 0) + return; + + /* get_cylindersize(dev, fd, silent); */ + if (!ioctl(fd, HDIO_GETGEO, &g)) + printf("%s: %d cylinders, %d heads, %d sectors/track\n", + dev, g.cylinders, g.heads, g.sectors); + else + printf("%s: unknown geometry\n", dev); +} + +/* for compatibility with earlier fdisk: provide option -s */ +void +do_size (char *dev, int silent) { + int fd, size; + + fd = my_open(dev, 0, silent); + if (fd < 0) + return; + + if(ioctl(fd, BLKGETSIZE, &size)) { + if(!silent) { + perror(dev); + fatal("BLKGETSIZE ioctl failed for %s\n", dev); + } + return; + } + + size /= 2; /* convert sectors to blocks */ + if (silent) + printf("%s: %d\n", dev, size); + else + printf("%d\n", size); + + total_size += size; +} + +/* + * Activate: usually one wants to have a single primary partition + * to be active. OS/2 fdisk makes non-bootable logical partitions + * active - I don't know what that means to OS/2 Boot Manager. + * + * Call: activate /dev/hda 2 5 7 make these partitions active + * and the remaining ones inactive + * Or: fdisk -A /dev/hda 2 5 7 + * + * If only a single partition must be active, one may also use the form + * fdisk -A2 /dev/hda + * + * With "activate /dev/hda" or "fdisk -A /dev/hda" the active partitions + * are listed but not changed. To get zero active partitions, use + * "activate /dev/hda none" or "fdisk -A /dev/hda none". + * Use something like `echo ",,,*" | fdisk -N2 /dev/hda' to only make + * /dev/hda2 active, without changing other partitions. + * + * A warning will be given if after the change not precisely one primary + * partition is active. + * + * The present syntax was chosen to be (somewhat) compatible with the + * activate from the LILO package. + */ +void +set_active (struct disk_desc *z, char *pnam) { + int pno; + + pno = asc_to_index(pnam, z); + z->partitions[pno].p.bootable = 0x80; +} + +void +do_activate (char **av, int ac, char *arg) { + char *dev = av[0]; + int fd; + int rw, i, pno, lpno; + struct disk_desc *z; + + z = &oldp; + + rw = (!no_write && (arg || ac > 1)); + fd = my_open(dev, rw, 0); + + free_sectors(); + get_cylindersize(dev, fd, 1); + get_partitions(dev, fd, z); + + if (!arg && ac == 1) { + /* list active partitions */ + for (pno=0; pno < z->partno; pno++) { + if (z->partitions[pno].p.bootable) { + lpno = index_to_linux(pno, z); + if (pno == linux_to_index(lpno, z)) + printf("%s%d\n", dev, lpno); + else + printf("%s#%d\n", dev, pno); + if (z->partitions[pno].p.bootable != 0x80) + warn("bad active byte: 0x%x instead of 0x80\n", + z->partitions[pno].p.bootable); + } + } + } else { + /* clear `active byte' everywhere */ + for (pno=0; pno < z->partno; pno++) + z->partitions[pno].p.bootable = 0; + + /* then set where desired */ + if (ac == 1) + set_active(z, arg); + else for(i=1; i<ac; i++) + set_active(z, av[i]); + + /* then write to disk */ + if(write_partitions(dev, fd, z)) + warn("Done\n\n"); + else + exit_status = 1; + } + i = 0; + for (pno=0; pno < z->partno && pno < 4; pno++) + if (z->partitions[pno].p.bootable) + i++; + if (i != 1) + warn("You have %d active primary partitions. This does not matter for LILO,\n" + "but the DOS MBR will only boot a disk with 1 active partition.\n", i); +} + +void +set_unhidden (struct disk_desc *z, char *pnam) { + int pno; + unsigned char id; + + pno = asc_to_index(pnam, z); + id = z->partitions[pno].p.sys_type; + if (id == 0x11 || id == 0x14 || id == 0x16 || id == 0x17) + id -= 0x10; + else + fatal("partition %s has id %x and is not hidden\n", pnam, id); + z->partitions[pno].p.sys_type = id; +} + +/* + * maybe remove and make part of --change-id + */ +void +do_unhide (char **av, int ac, char *arg) { + char *dev = av[0]; + int fd, rw, i; + struct disk_desc *z; + + z = &oldp; + + rw = !no_write; + fd = my_open(dev, rw, 0); + + free_sectors(); + get_cylindersize(dev, fd, 1); + get_partitions(dev, fd, z); + + /* unhide where desired */ + if (ac == 1) + set_unhidden(z, arg); + else for(i=1; i<ac; i++) + set_unhidden(z, av[i]); + + /* then write to disk */ + if(write_partitions(dev, fd, z)) + warn("Done\n\n"); + else + exit_status = 1; +} + +void do_change_id(char *dev, char *pnam, char *id) { + int fd, rw, pno; + struct disk_desc *z; + unsigned long i; + + z = &oldp; + + rw = !no_write; + fd = my_open(dev, rw, 0); + + free_sectors(); + get_cylindersize(dev, fd, 1); + get_partitions(dev, fd, z); + + pno = asc_to_index(pnam, z); + if (id == 0) { + printf("%x\n", z->partitions[pno].p.sys_type); + return; + } + i = strtoul(id, NULL, 16); + if (i > 255) + fatal("Bad Id %x\n", i); + z->partitions[pno].p.sys_type = i; + + if(write_partitions(dev, fd, z)) + warn("Done\n\n"); + else + exit_status = 1; +} + +void +do_reread(char *dev) { + int fd; + + fd = my_open(dev, 0, 0); + if(reread_ioctl(fd)) + printf("This disk is currently in use.\n"); +} + +/* + * I. Writing the new situation + */ + +void +do_fdisk(char *dev){ + int fd; + int c, answer; + struct stat statbuf; + int interactive = isatty(0); + struct disk_desc *z; + + if (stat(dev, &statbuf) < 0) { + perror(dev); + fatal("Fatal error: cannot find %s\n", dev); + } + if (!S_ISBLK(statbuf.st_mode)) { + warn("Warning: %s is not a block device\n", dev); + } + fd = my_open(dev, !no_write, 0); + + if(!no_write && !no_reread) { + warn("Checking that no-one is using this disk right now ...\n"); + if(reread_ioctl(fd)) { + printf(" +This disk is currently in use - repartitioning is probably a bad idea. +Umount all file systems, and swapoff all swap partitions on this disk. +Use the --no-reread flag to suppress this check.\n"); + if (!force) { + printf("Use the --force flag to overrule all checks.\n"); + exit(1); + } + } else + warn("OK"); + } + + z = &oldp; + + free_sectors(); + get_cylindersize(dev, fd, 0); + get_partitions(dev, fd, z); + + printf("Old situation:\n"); + out_partitions(dev, z); + + if (one_only && (one_only_pno = linux_to_index(one_only, z)) < 0) + fatal("Partition %d does not exist, cannot change it\n", one_only); + + z = &newp; + + while(1) { + + read_input(dev, interactive, z); + + printf("New situation:\n"); + out_partitions(dev, z); + + if (!partitions_ok(z) && !force) { + if(!interactive) + fatal("I don't like these partitions - nothing changed.\n" + "(If you really want this, use the --force option.)\n"); + else + printf("I don't like this - probably you should answer No\n"); + } + ask: + if (interactive) { + if (no_write) + printf("Are you satisfied with this? [ynq] "); + else + printf("Do you want to write this to disk? [ynq] "); + answer = c = getchar(); + while (c != '\n' && c != EOF) + c = getchar(); + if (c == EOF) + printf("\nfdisk: premature end of input\n"); + if (c == EOF || answer == 'q' || answer == 'Q') { + fatal("Quitting - nothing changed\n"); + } else if (answer == 'n' || answer == 'N') { + continue; + } else if (answer == 'y' || answer == 'Y') { + break; + } else { + printf("Please answer one of y,n,q\n"); + goto ask; + } + } else + break; + } + + if(write_partitions(dev, fd, z)) + printf("Successfully wrote the new partition table\n\n"); + else + exit_status = 1; + + reread_disk_partition(dev, fd); + + warn("If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)\n" + "to zero the first 512 bytes: dd if=/dev/zero of=/dev/foo7 bs=512 count=1\n" + "(See fdisk(8).)\n"); + + sync(); /* superstition */ + sleep(3); + exit(exit_status); +} diff --git a/disk-utils/sfdisk.examples b/disk-utils/sfdisk.examples new file mode 100644 index 000000000..13e671d48 --- /dev/null +++ b/disk-utils/sfdisk.examples @@ -0,0 +1,264 @@ +Examples of the use of sfdisk 3.0 (to partition a disk) +Input lines have fields <start>,<size>,<type>... - see sfdisk.8. +Usually no <start> is given, and input lines start with a comma. + +Before doing anything with a disk, make sure it is not in use; +unmount all its file systems, and say swapoff to its swap partitions. +(The final BLKRRPART ioctl will fail if anything else still uses +the disk, and you will have to reboot. It is easier to first make +sure that nothing uses the disk, e.g., by testing: + % umount /dev/sdb1 + % sfdisk -R /dev/sdb + BLKRRPART: Device or resource busy + * Device busy for revalidation (usage=2) + % swapoff /dev/sdb3 + % sfdisk -R /dev/sdb + * sdb: sdb1 < sdb5 sdb6 > sdb3 + % +Note that the starred messages are kernel messages, that may be +logged somewhere, or written to some other console. +In sfdisk 3.01 sfdisk automatically does this check, unless told not to.) + +1. One big partition: + sfdisk /dev/hda << EOF + ; + EOF + +(If there was garbage on the disk before, you may get error messages +like: `ERROR: sector 0 does not have an msdos signature' +and `/dev/hda: unrecognized partition'. This does not matter +if you write an entirely fresh partition table anyway.) + +The output will be: +----------------------------------------------------------------------- +Old situation: +... +New situation: +Units = cylinders of 208896 bytes, blocks of 1024 bytes, counting from 0 + + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 1023 1024- 208895+ 83 Linux native +Successfully wrote the new partition table + hda: hda1 +----------------------------------------------------------------------- +Writing and rereading the partition table takes a few seconds - +don't be alarmed if nothing happens for six seconds or so. + + +2. Three primary partitions: two of size 50MB and the rest: + sfdisk /dev/hda -uM << EOF + ,50 + ,50 + ; + EOF +----------------------------------------------------------------------- +New situation: +Units = megabytes of 1048576 bytes, blocks of 1024 bytes, counting from 0 + + Device Boot Start End MB #blocks Id System +/dev/hda1 0+ 50- 51- 51203+ 83 Linux native +/dev/hda2 50+ 100- 51- 51204 83 Linux native +/dev/hda3 100+ 203 104- 106488 83 Linux native +Successfully wrote the new partition table + hda: hda1 hda2 hda3 +----------------------------------------------------------------------- +/dev/hda1 is one block (in fact only half a block) shorter than +/dev/hda2 because its start had to be shifted away from zero in +order to leave room for the Master Boot Record (MBR). + + +3. A 1MB OS2 Boot Manager partition, a 50MB DOS partition, + and three extended partitions (DOS D:, Linux swap, Linux): + sfdisk /dev/hda -uM << EOF + ,1,a + ,50,6 + ,,E + ; + ,20,4 + ,16,S + ; + EOF +----------------------------------------------------------------------- + Device Boot Start End MB #blocks Id System +/dev/hda1 0+ 1- 2- 1223+ a OS/2 Boot Manager +/dev/hda2 1+ 51- 51- 51204 6 DOS 16-bit FAT >=32M +/dev/hda3 51+ 203 153- 156468 5 Extended +/dev/hda4 0 - 0 0 0 Empty +/dev/hda5 51+ 71- 21- 20603+ 4 DOS 16-bit FAT <32M +/dev/hda6 71+ 87- 17- 16523+ 82 Linux swap +/dev/hda7 87+ 203 117- 119339+ 83 Linux native +Successfully wrote the new partition table + hda: hda1 hda2 hda3 < hda5 hda6 hda7 > +----------------------------------------------------------------------- +All these rounded numbers look better in cylinder units: + % sfdisk -l /dev/hda +----------------------------------------------------------------------- + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager +/dev/hda2 6 256 251 51204 6 DOS 16-bit FAT >=32M +/dev/hda3 257 1023 767 156468 5 Extended +/dev/hda4 0 - 0 0 0 Empty +/dev/hda5 257+ 357 101- 20603+ 4 DOS 16-bit FAT <32M +/dev/hda6 358+ 438 81- 16523+ 82 Linux swap +/dev/hda7 439+ 1023 585- 119339+ 83 Linux native +----------------------------------------------------------------------- +But still - why does /dev/hda5 not start on a cylinder boundary? +Because it is contained in an extended partition that does. +Of the chain of extended partitions, usually only the first is +shown. (The others have no name under Linux anyway.) But +these additional extended partitions can be made visible: + % sfdisk -l -x /dev/hda +----------------------------------------------------------------------- + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager +/dev/hda2 6 256 251 51204 6 DOS 16-bit FAT >=32M +/dev/hda3 257 1023 767 156468 5 Extended +/dev/hda4 0 - 0 0 0 Empty + +/dev/hda5 257+ 357 101- 20603+ 4 DOS 16-bit FAT <32M + - 358 1023 666 135864 5 Extended + - 257 256 0 0 0 Empty + - 257 256 0 0 0 Empty + +/dev/hda6 358+ 438 81- 16523+ 82 Linux swap + - 439 1023 585 119340 5 Extended + - 358 357 0 0 0 Empty + - 358 357 0 0 0 Empty + +/dev/hda7 439+ 1023 585- 119339+ 83 Linux native + - 439 438 0 0 0 Empty + - 439 438 0 0 0 Empty + - 439 438 0 0 0 Empty +----------------------------------------------------------------------- + +Why the empty 4th input line? The description of the extended partitions +starts after that of the four primary partitions. +You force an empty partition with a ",0" input line, but here all +space was divided already, so the fourth partition became empty +automatically. + +How did I know about 4,6,a,E,S? Well, E,S,L stand for Extended, +Swap and Linux. The other values are hexadecimal and come from +the table: + % sfdisk -T + Id Name + + 0 Empty + 1 DOS 12-bit FAT + 2 XENIX root + 3 XENIX usr + 4 DOS 16-bit FAT <32M + 5 Extended + 6 DOS 16-bit FAT >=32M + 7 OS/2 HPFS or QNX or Advanced UNIX + 8 AIX data + 9 AIX boot or Coherent + a OS/2 Boot Manager + ... + + +4. Preserving the sectors changed by sfdisk. + % sfdisk -O save-hdd-partition-sectors /dev/hda + ... + will write the sectors overwritten by sfdisk to file. + If you notice that you trashed some partition, you may + be able to restore things by + % sfdisk -I save-hdd-partition-sectors /dev/hda + % + +5. Preserving some old partitions. + % sfdisk -N2 /dev/hda + ... + will only change the partition /dev/hda2, and leave the rest + unchanged. The most obvious application is to change an Id: + % sfdisk -N7 /dev/hda + ,,63 + % +----------------------------------------------------------------------- +Old situation: + + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager +... +/dev/hda6 358+ 438 81- 16523+ 82 Linux swap +/dev/hda7 439+ 1023 585- 119339+ 83 Linux native + +New situation: + + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager +... +/dev/hda6 358+ 438 81- 16523+ 82 Linux swap +/dev/hda7 439+ 1023 585- 119339+ 63 GNU HURD +----------------------------------------------------------------------- + Note that changing a logical partition into an empty partition + will decrease the number of all subsequent logical partitions. + +6. Deleting a partition. +At first I thought of having an option -X# for deleting partitions, +but there are several ways in which a partition can be deleted, and +it is probably better to handle this just as a general change. + % sfdisk -d /dev/hda > ohda +will write the current tables on the file `ohda'. +----------------------------------------------------------------------- +% cat ohda +# partition table of /dev/hda +unit: sectors + +/dev/hda1 : start= 1, size= 40799, Id= 5 +/dev/hda2 : start= 40800, size= 40800, Id=83 +/dev/hda3 : start= 81600, size= 336192, Id=83 +/dev/hda4 : start= 0, size= 0, Id= 0 +/dev/hda5 : start= 2, size= 40798, Id=83 +----------------------------------------------------------------------- +In order to delete the partition on /dev/hda3, edit this file +and feed the result to sfdisk again. +----------------------------------------------------------------------- +% emacs ohda +% cat ohda +# partition table of /dev/hda +unit: sectors + +/dev/hda1 : start= 1, size= 40799, Id= 5 +/dev/hda2 : start= 40800, size= 40800, Id=83 +/dev/hda3 : start= 0, size= 0, Id= 0 +/dev/hda4 : start= 0, size= 0, Id= 0 +/dev/hda5 : start= 2, size= 40798, Id=83 +% sfdisk /dev/hda < ohda +Old situation: +Units = cylinders of 208896 bytes, blocks of 1024 bytes, counting from 0 + + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 99 100- 20399+ 5 Extended +/dev/hda2 100 199 100 20400 83 Linux native +/dev/hda3 200 1023 824 168096 83 Linux native +/dev/hda4 0 - 0 0 0 Empty +/dev/hda5 0+ 99 100- 20399 83 Linux native +New situation: +Units = sectors of 512 bytes, counting from 0 + + Device Boot Start End #sectors Id System +/dev/hda1 1 40799 40799 5 Extended +/dev/hda2 40800 81599 40800 83 Linux native +/dev/hda3 0 - 0 0 Empty +/dev/hda4 0 - 0 0 Empty +/dev/hda5 2 40799 40798 83 Linux native +Successfully wrote the new partition table +% sfdisk -l -V /dev/hda + +Disk /dev/hda: 12 heads, 34 sectors, 1024 cylinders +Units = cylinders of 208896 bytes, blocks of 1024 bytes, counting from 0 + + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 99 100- 20399+ 5 Extended +/dev/hda2 100 199 100 20400 83 Linux native +/dev/hda3 0 - 0 0 0 Empty +/dev/hda4 0 - 0 0 0 Empty +/dev/hda5 0+ 99 100- 20399 83 Linux native +/dev/hda: OK +----------------------------------------------------------------------- +This is a good way of making changes: dump the current status +to file, edit the file, and feed it to sfdisk. +Preserving the file on some other disk could be useful: +if ever the MBR gets thrashed it can be used to restore +the old situation. |