diff options
author | Karel Zak | 2006-12-07 00:25:33 +0100 |
---|---|---|
committer | Karel Zak | 2006-12-07 00:25:33 +0100 |
commit | 726f69e29ca9d4842f3acb20fffd2466fda62c09 (patch) | |
tree | abbc1b6e9bfb0dfe32e81a83648e261ccb2d5a5f /disk-utils | |
parent | Imported from util-linux-2.2 tarball. (diff) | |
download | kernel-qcow2-util-linux-726f69e29ca9d4842f3acb20fffd2466fda62c09.tar.gz kernel-qcow2-util-linux-726f69e29ca9d4842f3acb20fffd2466fda62c09.tar.xz kernel-qcow2-util-linux-726f69e29ca9d4842f3acb20fffd2466fda62c09.zip |
Imported from util-linux-2.5 tarball.
Diffstat (limited to 'disk-utils')
-rw-r--r-- | disk-utils/Makefile | 34 | ||||
-rw-r--r-- | disk-utils/README.fdisk | 22 | ||||
-rw-r--r-- | disk-utils/README.fdisk.alpha | 16 | ||||
-rw-r--r-- | disk-utils/README.fdisk.bsd | 28 | ||||
-rw-r--r-- | disk-utils/cfdisk.8 | 2 | ||||
-rw-r--r-- | disk-utils/cfdisk.8.bak | 407 | ||||
-rw-r--r-- | disk-utils/cfdisk.c | 8 | ||||
-rw-r--r-- | disk-utils/cfdisk.c.bak | 2066 | ||||
-rw-r--r-- | disk-utils/cfdisk.c.orig | 2066 | ||||
-rw-r--r-- | disk-utils/fdformat.c | 2 | ||||
-rw-r--r-- | disk-utils/fdisk.8 | 2 | ||||
-rw-r--r-- | disk-utils/fdisk.c | 280 | ||||
-rw-r--r-- | disk-utils/fdisk.h | 47 | ||||
-rw-r--r-- | disk-utils/fdisklabel.c | 801 | ||||
-rw-r--r-- | disk-utils/fdisklabel.h | 233 | ||||
-rw-r--r-- | disk-utils/fsck.minix.8 | 3 | ||||
-rw-r--r-- | disk-utils/llseek.c | 17 | ||||
-rw-r--r-- | disk-utils/mkfs.8 | 108 | ||||
-rw-r--r-- | disk-utils/mkfs.c | 332 | ||||
-rw-r--r-- | disk-utils/mkfs.minix.8 | 3 | ||||
-rw-r--r-- | disk-utils/mkfs.minix.c | 57 | ||||
-rw-r--r-- | disk-utils/mkswap.8 | 56 | ||||
-rw-r--r-- | disk-utils/mkswap.c | 69 |
23 files changed, 6135 insertions, 524 deletions
diff --git a/disk-utils/Makefile b/disk-utils/Makefile index 854e1ec9d..739d12834 100644 --- a/disk-utils/Makefile +++ b/disk-utils/Makefile @@ -1,6 +1,6 @@ # Makefile -- Makefile for util-linux Linux utilities # Created: Sat Dec 26 20:09:40 1992 -# Revised: Wed Feb 22 16:09:35 1995 by faith@cs.unc.edu +# Revised: Fri Oct 6 21:02:21 1995 by r.faith@ieee.org # Copyright 1992, 1993, 1994, 1995 Rickard E. Faith (faith@cs.unc.edu) # @@ -8,15 +8,17 @@ include ../MCONFIG # Where to put man pages? -MAN8= cfdisk.8 fdformat.8 fdisk.8 frag.8 fsck.minix.8 \ - mkfs.8 mkfs.minix.8 mkswap.8 setfdprm.8 +MAN8= cfdisk.8 fdformat.8 fsck.minix.8 \ + mkfs.8 mkfs.minix.8 mkswap.8 setfdprm.8 + +MAN8.FDISK= fdisk.8 # Where to put binaries? # See the "install" rule for the links. . . -SBIN= cfdisk fdisk fsck.minix mkfs mkfs.minix mkswap +SBIN= cfdisk fsck.minix mkfs mkfs.minix mkswap -USRSBIN= frag +SBIN.FDISK= fdisk USRBIN= fdformat setfdprm @@ -24,29 +26,31 @@ USRBIN= fdformat setfdprm ETC= fdprm -all: $(SBIN) $(USRSBIN) $(USRBIN) +ifeq "$(HAVE_FDISK)" "no" +SBIN:=$(SBIN) $(SBIN.FDISK) +MAN8:=$(MAN8) $(MAN8.FDISK) +endif -cfdisk: cfdisk.c llseek.o - $(CC) $(CFLAGS) $(LDFLAGS) $< llseek.o -o $@ -lcurses -ltermcap -lm +all: $(SBIN) $(USRBIN) -%.o: %.c - $(CC) -c $(CFLAGS) $< -o $@ +cfdisk: cfdisk.o llseek.o + $(CC) $(LDFLAGS) $^ -o $@ -lcurses -ltermcap -lm # Rules for everything else fdformat: fdformat.o -fdisk: fdisk.o llseek.o -frag: frag.o +fdisk: fdisk.o fdisklabel.o llseek.o fsck.minix: fsck.minix.o mkfs: mkfs.o mkfs.minix: mkfs.minix.o mkswap: mkswap.o setfdprm: setfdprm.o +fdisk.o: fdisk.c fdisk.h +fdisklabel.o: fdisklabel.c fdisk.h install: all - $(INSTALLDIR) $(SBINDIR) $(USRSBINDIR) $(ETCDIR) + $(INSTALLDIR) $(SBINDIR) $(USRBINDIR) $(ETCDIR) $(INSTALLBIN) $(SBIN) $(SBINDIR) - $(INSTALLBIN) $(USRSBIN) $(USRSBINDIR) $(INSTALLBIN) $(USRBIN) $(USRBINDIR) $(INSTALLDAT) $(ETC) $(ETCDIR) $(INSTALLDIR) $(MAN8DIR) @@ -54,4 +58,4 @@ install: all .PHONY: clean clean: - -rm -f *.o *~ core $(SBIN) $(USRSBIN) $(USRBIN) + -rm -f *.o *~ core $(SBIN) $(USRBIN) diff --git a/disk-utils/README.fdisk b/disk-utils/README.fdisk index 9e64508ed..40f54b4b9 100644 --- a/disk-utils/README.fdisk +++ b/disk-utils/README.fdisk @@ -114,7 +114,7 @@ Dividing up your disk It is a good idea to plan ahead before you start creating partitions on your disk. If you set aside a partition for some purpose, it is not -easy to change its size: you must all the data from the partition, +easy to change its size: you must backup all the data from the partition, whether to floppies, to another partition, to another hard disk, or somewhere else; then you must edit the table which describes this partition, so changing its size; then you must reboot and initialise @@ -309,8 +309,8 @@ display/entry units are sectors. The Verify command is useful because - 1. It warns you if anything is wrong. *Always* give a Verify command - before writing any changes to disk. + 1. It warns you if anything is wrong. *Always* do a Verify command + to check your work before writing any changes to disk. 2. It reports how many unallocated sectors there are on the disk. @@ -369,20 +369,22 @@ unless there are sectors available inside the extended partition. If space is available, you are prompted for the first cylinder: - First sector (237-977): _ + First sector ([237]-977): _ The limits are the lowest and the highest cylinders in which sectors -are available in the appropriate part of the disk. Not all numbers in +are available in the appropriate part of the disk. The square-bracketed +number is what you'll get if you simply press enter. Not all numbers in this range are necessarily available: they may fall inside an existing partition. If you select a cylinder which is already in use, you are told off and prompted again for the first cylinder. After selecting the first cylinder, you are prompted again: - Last cylinder or +size or +sizeM or +sizeK (237-836): _ + Last cylinder or +size or +sizeM or +sizeK (237-[836]): _ The limits are the cylinder you have chosen as the first cylinder, and the highest cylinder which contains a legitimate upper boundary for -the new partition. In other words, all numbers in the given range are +the new partition. The square-bracketed number is what you'll get if +you simply press enter. In other words, all numbers in the given range are legitimate, unlike those in the first range of cylinders. You may also specify the size of a partition in megabytes, kilobytes, or in the current units (cylinders or sectors). A plus sign `+' indicates that @@ -395,7 +397,7 @@ possible answers to the last cylinder request above are Make cylinder 700 the last cylinder in the partition. +300 - Make cylinder 537 the last cylinder in the partition. + Make cylinder 237 + 300 = 537 the last cylinder in the partition. +15m Make the partition at least 15 megabytes in size. @@ -404,7 +406,7 @@ possible answers to the last cylinder request above are Make the partition at least 12,500 kilobytes in size. If you specify a size which is too large or an end which is out of -range, the prompt is simply repeated. +range, fdisk complains and repeats the prompt. Adding or deleting partitions has no effect unless you subsequently give the Write command. Please remember to give the Verify command @@ -544,7 +546,7 @@ Warnings for `fdisk' users In general, you should not use this `fdisk' program to create partitions for other operating systems, only for Linux. Nor should you -use `fdisk' commands from other operating systems do create partitions +use `fdisk' commands from other operating systems to create partitions for Linux. DR-DOS 5.0 and 6.0 are reported to have difficulties with partition diff --git a/disk-utils/README.fdisk.alpha b/disk-utils/README.fdisk.alpha new file mode 100644 index 000000000..da6e87342 --- /dev/null +++ b/disk-utils/README.fdisk.alpha @@ -0,0 +1,16 @@ + +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 new file mode 100644 index 000000000..705df90f8 --- /dev/null +++ b/disk-utils/README.fdisk.bsd @@ -0,0 +1,28 @@ + +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/cfdisk.8 b/disk-utils/cfdisk.8 index cb23149fb..010c370dd 100644 --- a/disk-utils/cfdisk.8 +++ b/disk-utils/cfdisk.8 @@ -11,7 +11,7 @@ .\" permission notice identical to this one. .\" .\" " for hilit mode -.TH CFDISK 8 "25 April 1994" "The BOGUS Linux Release" "Linux Programmer's Manual" +.TH CFDISK 8 "3 June 1995" "The BOGUS Linux Release" "Linux Programmer's Manual" .SH NAME cfdisk \- Curses based disk partition table manipulator for Linux .SH SYNOPSIS diff --git a/disk-utils/cfdisk.8.bak b/disk-utils/cfdisk.8.bak new file mode 100644 index 000000000..cb23149fb --- /dev/null +++ b/disk-utils/cfdisk.8.bak @@ -0,0 +1,407 @@ +.\" cfdisk.8 -- man page for cfdisk +.\" Copyright 1994 Kevin E. Martin (martin@cs.unc.edu) +.\" +.\" Permission is granted to make and distribute verbatim copies of this +.\" manual provided the copyright notice and this permission notice are +.\" preserved on all copies. +.\" +.\" Permission is granted to copy and distribute modified versions of this +.\" manual under the conditions for verbatim copying, provided that the +.\" entire resulting derived work is distributed under the terms of a +.\" permission notice identical to this one. +.\" +.\" " for hilit mode +.TH CFDISK 8 "25 April 1994" "The BOGUS Linux Release" "Linux Programmer's Manual" +.SH NAME +cfdisk \- Curses based disk partition table manipulator for Linux +.SH SYNOPSIS +.BI "cfdisk [ \-avz ] [ \-c " cylinders " ] [ \-h " heads " ]" +.BI "[ \-s " sectors-per-track " ] [ -P " opt " ] [ " device " ]" +.SH DESCRIPTION +.B cfdisk +is a curses based program for partitioning a hard disk drive. The +.I device +can be any one of the following: +.sp +.nf +.RS +/dev/hda [default] +/dev/hdb +/dev/sda +/dev/sdb +/dev/sdc +/dev/sdd +.RE +.fi + +.B cfdisk +first tries to read the geometry of the hard disk. If it fails, an +error message is displayed and +.B cfdisk +exits. This should only happen when partitioning a SCSI drive on an +adapter without a BIOS. To correct this problem, you can set the +.IR cylinders ", " heads " and " sectors-per-track +on the command line. Next, +.B cfdisk +tries to read the current partition table from the disk drive. If it +is unable to figure out the partition table, an error is displayed and +the program will exit. This might also be caused by incorrect +geometry information, and can be overridden on the command line. +Another way around this problem is with the +.B \-z +option. This will ignore the partition table on the disk. + +The main display is composed of four sections, from top to bottom: the +header, the partitions, the command line and a warning line. The +header contains the program name and version number followed by the +disk drive and its geometry. The partitions section always displays +the current partition table. The command line is the place where +commands and text are entered. The available commands are usually +displayed in brackets. The warning line is usually empty except when +there is important information to be displayed. The current partition +is highlighted with reverse video (or an arrow if the +.B \-a +option is given). All partition specific commands apply to the +current partition. + +The format of the partition table in the partitions section is, from +left to right: Name, Flags, Partition Type, Filesystem Type and Size. +The name is the partition device name. The flags can be +.IR Boot , +which designates a bootable partition or +.IR NC , +which stands for "Not Compatible with DOS or OS/2". DOS, OS/2 and +possibly other operating systems require the first sector of the first +partition on the disk and all logical partitions to begin on the +second head. This wastes the second through the last sector of the +first track of the first head (the first sector is taken by the +partition table itself). +.B cfdisk +allows you to recover these "lost" sectors with the maximize command +.RB ( m ). +.I Note: +.BR fdisk (8) +and some early versions of DOS create all partitions with the number +of sectors already maximized. For more information, see the maximize +command below. The partition type can be one of +.IR Primary " or " Logical . +For unallocated space on the drive, the partition type can also be +.IR Pri/Log , +or empty (if the space is unusable). The filesystem type section +displays the name of the filesystem used on the partition, if known. +If it is unknown, then +.I Unknown +and the hex value of the filesystem type are displayed. A special +case occurs when there are sections of the disk drive that cannot be +used (because all of the primary partitions are used). When this is +detected, the filesystem type is displayed as +.IR Unusable . +The size field displays the size of the partition in megabytes (by +default). It can also display the size in sectors and cylinders (see +the change units command below). If an asterisks +.RB ( * ) +appears after the size, this means that the partition is not aligned +on cylinder boundaries. +.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. + +The bottom line is that if you use cfdisk or fdisk 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 cfdisk to make a DOS +partition table entry for /dev/hda1, then (after exiting fdisk or cfdisk +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. + +.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 resutls, 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. + +.SH COMMANDS +.B cfdisk +commands can be entered by pressing the desired key (pressing +.I Enter +after the command is not necessary). Here is a list of the available +commands: +.TP +.B b +Toggle bootable flag of the current partition. This allows you to +select which primary partition is bootable on the drive. +.TP +.B d +Delete the current partition. This will convert the current partition +into free space and merge it with any free space immediately +surrounding the current partition. A partition already marked as free +space or marked as unusable cannot be deleted. +.TP +.B g +Change the disk geometry (cylinders, heads, or sectors-per-track). +.B WARNING: +This option should only be used by people who know what they are +doing. A command line option is also available to change the disk +geometry. While at the change disk geometry command line, you can +choose to change cylinders +.RB ( c ), +heads +.RB ( h ), +and sectors per track +.RB ( s ). +The default value will be printed at the prompt which you can accept +by simply pressing the +.I Enter +key, or you can exit without changes by pressing the +.I ESC +key. If you want to change the default value, simply enter the +desired value and press +.IR Enter . +The altered disk parameter values do not take effect until you return +the main menu (by pressing +.IR Enter " or " ESC +at the change disk geometry command line. If you change the geometry +such that the disk appears larger, the extra sectors are added at the +end of the disk as free space. If the disk appears smaller, the +partitions that are beyond the new last sector are deleted and the +last partition on the drive (or the free space at the end of the +drive) is made to end at the new last sector. +.TP +.B h +Print the help screen. +.TP +.B m +Maximize disk usage of the current partition. This command will +recover the the unused space between the partition table and the +beginning of the partition, but at the cost of making the partition +incompatible with DOS, OS/2 and possibly other operating systems. +This option will toggle between maximal disk usage and DOS, OS/2, +etc. compatible disk usage. The default when creating a partition is +to create DOS, OS/2, etc. compatible partitions. +.TP +.B n +Create new partition from free space. If the partition type is +.IR Primary " or " Logical , +a partition of that type will be created, but if the partition type is +.IR Pri/Log , +you will be prompted for the type you want to create. Be aware that +(1) there are only four slots available for primary partitions and (2) +since there can be only one extended partition, which contains all of +the logical drives, all of the logical drives must be contiguous (with +no intervening primary partition). +.B cfdisk +next prompts you for the size of the partition you want to create. +The default size, equal to the entire free space of the current +partition, is display in megabytes. You can either press the +.I Enter +key to accept the default size or enter a different size at the +prompt. +.B cfdisk +accepts size entries in megabytes +.RB ( M ) +[default], kilobytes +.RB ( K ), +cylinders +.RB ( C ) +and sectors +.RB ( S ) +by entering the number immediately followed by one of +.RB ( M ", " K ", " C " or " S ). +If the partition fills the free space available, the partition is +created and you are returned to the main command line. Otherwise, the +partition can be created at the beginning or the end of the free +space, and +.B cfdisk +will ask you to choose where to place the partition. After the +partition is created, +.B cfdisk +automatically adjusts the other partition's partition types if all of +the primary partitions are used. +.TP +.B p +Print the partition table to the screen or to a file. There are +several different formats for the partition that you can choose from: +.sp +.RS +.TP +.B r +Raw data format (exactly what would be written to disk) +.TP +.B s +Partition table in sector order format +.TP +.B t +Partition table in raw format +.RE + +.RS +The +.I raw data format +will print the sectors that would be written to disk if a +.BR w rite +command is selected. First, the primary partition table is printed, +followed by the partition tables associated with each logical +partition. The data is printed in hex byte by byte with 16 bytes per +line. + +The +.I partition table in sector order format +will print the partition table ordered by sector number. The fields, +from left to right, are the number of the partition, the partition +type, the first sector, the last sector, the offset from the first +sector of the partition to the start of the data, the length of the +partition, the filesystem type (with the hex value in parenthesis), +and the flags (with the hex value in parenthesis). In addition to the +primary and logical partitions, free and unusable space is printed and +the extended partition is printed before the first logical partition. + +If a partition does not start or end on a cylinder boundary or if the +partition length is not divisible by the cylinder size, an asterisks +.RB ( * ) +is printed after the non-aligned sector number/count. This usually +indicates that a partition was created by an operating system that +either does not align partitions to cylinder boundaries or that used +different disk geometry information. If you know the disk geometry of +the other operating system, you could enter the geometry information +with the change geometry command +.RB ( g ). + +For the first partition on the disk and for all logical partitions, if +the offset from the beginning of the partition is not equal to the +number of sectors per track (i.e., the data does not start on the +first head), a number sign +.RB ( # ) +is printed after the offset. For the remaining partitions, if the +offset is not zero, a number sign will be printed after the offset. +This corresponds to the +.I NC +flag in the partitions section of the main display. + +The +.I partition table in raw format +will print the partition table ordered by partition number. It will +leave out all free and unusable space. The fields, from left to +right, are the number of the partition, the flags (in hex), the +starting head, sector and cylinder, the filesystem ID (in hex), the +ending head, sector and cylinder, the starting sector in the partition +and the number of sectors in the partition. The information in this +table can be directly translated to the +.IR "raw data format" . + +The partition table entries only have 10 bits available to represent +the starting and ending cylinders. Thus, when the absolute starting +(ending) sector number is on a cylinder greater than 1023, the maximal +values for starting (ending) head, sector and cylinder are printed. +This is the method used by OS/2, and thus fixes the problems +associated with OS/2's fdisk rewriting the partition table when it is +not in this format. Since Linux and OS/2 use absolute sector counts, +the values in the starting and ending head, sector and cylinder are +not used. +.RE +.TP +.B q +Quit program. This will exit the program without writing any data to +disk. +.TP +.B t +Change the filesystem type. By default, new partitions are created as +.I Linux +partitions, but since +.B cfdisk +can create partitions for other operating systems, change partition +type allows you to enter the hex value of the filesystem you desire. +A list of the know filesystem types is displayed. You can type in the +filesystem type at the prompt or accept the default filesystem type +.RI [ Linux ]. +.TP +.B u +Change units of the partition size display. It will rotate through +megabytes, sectors and cylinders. +.TP +.B W +Write partition table to disk (must enter an upper case W). Since +this might destroy data on the disk, you must either confirm or deny +the write by entering `yes' or `no'. If you enter `yes', +.B cfdisk +will write the partition table to disk and the tell the kernel to +re-read the partition table from the disk. The re-reading of the +partition table works is most cases, but I have seen it fail. Don't +panic. It will be correct after you reboot the system. In all cases, +I still recommend rebooting the system--just to be safe. +.TP +.I Up Arrow +.TP +.I Down Arrow +Move cursor to the previous or next partition. If there are more +partitions than can be displayed on a screen, you can display the next +(previous) set of partitions by moving down (up) at the last (first) +partition displayed on the screen. +.TP +.I CTRL-L +Redraws the screen. In case something goes wrong and you cannot read +anything, you can refresh the screen from the main command line. +.TP +.B ? +Print the help screen. + +.RE +All of the commands can be entered with either upper or lower case +letters (except for +.BR W rites). +When in a sub-menu or at a prompt to enter a filename, you can hit the +.I ESC +key to return to the main command line. +.SH OPTIONS +.TP +.B \-a +Use an arrow cursor instead of reverse video for highlighting the +current partition. +.TP +.B \-v +Print the version number and copyright. +.TP +.B \-z +Start with zeroed partition table. This option is useful when you +want to repartition your entire disk. +.I Note: +this option does not zero the partition table on the disk; rather, it +simply starts the program without reading the existing partition +table. +.TP +.BI \-c " cylinders" +.TP +.BI \-h " heads" +.TP +.BI \-s " sectors-per-track" +Override the number of cylinders, heads and sectors per track read +from the BIOS. If your BIOS or adapter does not supply this +information or if it supplies incorrect information, use these options +to set the disk geometry values. +.TP +.BI \-P " opt" +Prints the partition table in specified formats. +.I opt +can be one or more of "r", "s" or "t". See the +.BR p rint +command (above) for more information on the print formats. +.SH "SEE ALSO" +fdisk(8) +.SH BUGS +The current version does not support multiple disks (future addition). +.SH AUTHOR +Kevin E. Martin (martin@cs.unc.edu) diff --git a/disk-utils/cfdisk.c b/disk-utils/cfdisk.c index 6c42f9c06..beb46e508 100644 --- a/disk-utils/cfdisk.c +++ b/disk-utils/cfdisk.c @@ -43,6 +43,7 @@ #include <curses.h> #include <signal.h> #include <math.h> +#include <string.h> #include <sys/ioctl.h> #include <linux/genhd.h> #include <linux/hdreg.h> @@ -59,7 +60,7 @@ extern ext2_loff_t ext2_llseek(unsigned int fd, unsigned int origin); -#define VERSION "0.8a BETA (>2GB)" +#define VERSION "0.8d BETA (>2GB)" #define DEFAULT_DEVICE "/dev/hda" #define ALTERNATE_DEVICE "/dev/sda" @@ -236,7 +237,7 @@ char *partition_type[NUM_PART_TYPES] = { /* The rest of these are taken from A. V. Le Blanc's (LeBlanc@mcc.ac.uk) * fdisk program. I do not know where they came from, but I include - * them for completeness. + * them for completeness. (With additions.) */ [0x02] = "XENIX root", @@ -247,7 +248,8 @@ char *partition_type[NUM_PART_TYPES] = { [0x51] = "Novell?", [0x52] = "Microport", [0x63] = "GNU HURD", - [0x64] = "Novell", + [0x64] = "Novell Netware 286", + [0x65] = "Novell Netware 386", [0x75] = "PC/IX", [0x80] = "Old MINIX", [0x93] = "Amoeba", diff --git a/disk-utils/cfdisk.c.bak b/disk-utils/cfdisk.c.bak new file mode 100644 index 000000000..3b9f22f58 --- /dev/null +++ b/disk-utils/cfdisk.c.bak @@ -0,0 +1,2066 @@ +/**************************************************************************** + * + * CFDISK + * + * cfdisk is a curses based disk drive partitioning program that can + * create partitions for a wide variety of operating systems including + * Linux, MS-DOS and OS/2. + * + * cfdisk was inspired by the fdisk program, by A. V. Le Blanc + * (LeBlanc@mcc.ac.uk). + * + * Copyright (C) 1994 Kevin E. Martin (martin@cs.unc.edu) + * + * cfdisk 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 2 of the License, or + * (at your option) any later version. + * + * cfdisk is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with cfdisk; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Created: Fri Jan 28 22:46:58 1994, martin@cs.unc.edu + * + ****************************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <unistd.h> +#include <ctype.h> +#include <errno.h> +#include <getopt.h> +#include <fcntl.h> +#include <curses.h> +#include <signal.h> +#include <math.h> +#include <sys/ioctl.h> +#include <linux/genhd.h> +#include <linux/hdreg.h> +#include <linux/fs.h> /* for BLKRRPART */ + +typedef long ext2_loff_t; +extern ext2_loff_t ext2_llseek(unsigned int fd, + ext2_loff_t offset, + unsigned int origin); + +#define VERSION "0.8 BETA (>2GB)" + +#define DEFAULT_DEVICE "/dev/hda" +#define ALTERNATE_DEVICE "/dev/sda" + +#define LINE_LENGTH 80 +#define MAXIMUM_PARTS 60 + +#define SECTOR_SIZE 512 + +#define MAX_CYLINDERS 65535 +#define MAX_HEADS 255 +#define MAX_SECTORS 63 + +#define ACTIVE_FLAG 0x80 +#define PART_TABLE_FLAG 0xAA55 + +#define UNUSABLE -1 +#define FREE_SPACE 0x00 +#define EXTENDED 0x05 +#define LINUX_MINIX 0x81 +#define LINUX_SWAP 0x82 +#define LINUX 0x83 + +#define ADD_EXISTS "This partition is already in use" +#define ADD_UNUSABLE "This partition is unusable" +#define DEL_EMPTY "Cannot delete an empty partition" +#define ID_EMPTY "Cannot change FS Type to empty" +#define ID_EXT "Cannot change FS Type to extended" +#define NEED_EXT "No room to create the extended partition" +#define NO_FLAGS "Cannot make this partition bootable" +#define NO_MORE_PARTS "No more partitions" +#define PRINT_OPEN_ERR "Cannot open file '%s'" +#define TWO_EXTENDEDS "Cannot create logical drive here -- would create two extended partitions" +#define TYPE_EMPTY "Cannot change the type of an empty partition" +#define BAD_COMMAND "Illegal command" +#define MAX_UNMAXABLE "Cannot maximize this partition" +#define BAD_OPEN "Cannot open disk drive" +#define BAD_SEEK "Cannot seek on disk drive" +#define BAD_READ "Cannot read disk drive" +#define BAD_WRITE "Cannot write disk drive" +#define BAD_GEOMETRY "Cannot read disk drive geometry" +#define BAD_PRIMARY "Bad primary partition" +#define BAD_LOGICAL "Bad logical partition" +#define BAD_CYLINDERS "Illegal cylinders value" +#define BAD_HEADS "Illegal heads value" +#define BAD_SECTORS "Illegal sectors value" +#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..." +#define YES_WRITE "Wrote partition table to disk" +#define NO_WRITE "Did not write partition table to disk" +#define RRPART_FAILED "Wrote partition table, but re-read table failed. Reboot to update table." + +#define PRI_OR_LOG -1 +#define PRIMARY -2 +#define LOGICAL -3 + +#define COL_ID_WIDTH 20 + +#define CR '\015' +#define ESC '\033' +#define DEL '\177' +#define BELL '\007' +/* '\014' == ^L */ +#define REDRAWKEY '\014' + +/* Display units */ +#define MEGABYTES 1 +#define SECTORS 2 +#define CYLINDERS 3 + +#define GS_DEFAULT -1 +#define GS_ESCAPE -2 + +#define PRINT_RAW_TABLE 1 +#define PRINT_SECTOR_TABLE 2 +#define PRINT_PARTITION_TABLE 4 + +#define IS_PRIMARY(p) ((p) >= 0 && (p) < 4) +#define IS_LOGICAL(p) ((p) > 3) + +#define round_int(d) ((double)((int)(d+0.5))) +#define ceiling(d) ((double)(((d) != (int)(d)) ? (int)(d+1.0) : (int)(d))) + +#define set_hsc(h,s,c,sector) \ +{ \ + s = sector % sectors + 1; \ + sector /= sectors; \ + h = sector % heads; \ + sector /= heads; \ + c = sector & 0xFF; \ + s |= (sector >> 2) & 0xC0;\ +} + +#define ALIGNMENT 2 +typedef union { + struct { + unsigned char align[ALIGNMENT]; + unsigned char b[SECTOR_SIZE]; + } c; + struct { + unsigned char align[ALIGNMENT]; + unsigned char buffer[0x1BE]; + struct partition part[4]; + unsigned short flag; + } p; +} partition_table; + +typedef struct { + int first_sector; /* first sector in partition */ + int last_sector; /* last sector in partition */ + int offset; /* offset from first sector to start of data */ + int flags; /* active == 0x80 */ + int id; /* filesystem type */ + int num; /* number of partition -- primary vs. logical */ +} partition_info; + +char *disk_device = DEFAULT_DEVICE; +int fd; +int heads = 0; +int sectors = 0; +int cylinders = 0; +int changed = FALSE; +int opened = FALSE; + +partition_info p_info[MAXIMUM_PARTS]; +partition_info ext_info; +int num_parts = 0; + +int logical = 0; +int logical_sectors[MAXIMUM_PARTS]; + +__sighandler_t old_SIGINT, old_SIGTERM; + +int arrow_cursor = FALSE; +int display_units = MEGABYTES; +int zero_table = FALSE; +int print_only = 0; + +/* Curses screen information */ +int cur_part = 0; +int warning_last_time = FALSE; +int defined = FALSE; +int COLUMNS = 80; +int NUM_ON_SCREEN = 1; + +/* Y coordinates */ +int HEADER_START = 0; +int DISK_TABLE_START = 5; +int WARNING_START = 23; +int COMMAND_LINE_Y = 21; + +/* X coordinates */ +int NAME_START = 4; +int FLAGS_START = 16; +int PTYPE_START = 30; +int FSTYPE_START = 45; +int SIZE_START = 70; +int COMMAND_LINE_X = 5; + +#define NUM_PART_TYPES 256 +char *partition_type[NUM_PART_TYPES] = { + [LINUX_MINIX] = "Linux/MINIX", + [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", + [0x0A] = "OS/2 Boot Manager", + [0xA5] = "BSD/386", + +/* The rest of these are taken from A. V. Le Blanc's (LeBlanc@mcc.ac.uk) + * fdisk program. I do not know where they came from, but I include + * them for completeness. + */ + + [0x02] = "XENIX root", + [0x03] = "XENIX usr", + [0x08] = "AIX", + [0x09] = "AIX bootable", + [0x40] = "Venix 80286", + [0x51] = "Novell?", + [0x52] = "Microport", + [0x63] = "GNU HURD", + [0x64] = "Novell", + [0x75] = "PC/IX", + [0x80] = "Old MINIX", + [0x93] = "Amoeba", + [0x94] = "Amoeba BBT", + [0xB7] = "BSDI fs", + [0xB8] = "BSDI swap", + [0xC7] = "Syrinx", + [0xDB] = "CP/M", + [0xE1] = "DOS access", + [0xE3] = "DOS R/O", + [0xF2] = "DOS secondary", + [0xFF] = "BBT" +}; + +void fdexit(int ret) +{ + if (opened) + close(fd); + + if (changed) { + fprintf(stderr, "Disk has been changed.\n"); + fprintf(stderr, "Reboot the system to ensure the partition " + "table is correctly updated.\n"); + + fprintf( stderr, "\nWARNING: If you have created or modified any\n" + "DOS 6.x partitions, please see the cfdisk manual\n" + "page for additional information.\n" ); + } + + + exit(ret); +} + +int get_string(char *str, int len, char *def) +{ + char c; + int i = 0; + int x, y; + int use_def = FALSE; + + getyx(stdscr, y, x); + clrtoeol(); + + str[i] = 0; + + if (def != NULL) { + mvaddstr(y, x, def); + move(y, x); + use_def = TRUE; + } + + refresh(); + while ((c = getch()) != '\n' && c != CR) { + switch (c) { + case ESC: + move(y, x); + clrtoeol(); + refresh(); + return GS_ESCAPE; + case DEL: + case '\b': + if (i > 0) { + str[--i] = 0; + mvaddch(y, x+i, ' '); + move(y, x+i); + } else if (use_def) { + clrtoeol(); + use_def = FALSE; + } else + putchar(BELL); + break; + default: + if (i < len && isprint(c)) { + mvaddch(y, x+i, c); + if (use_def) { + clrtoeol(); + use_def = FALSE; + } + str[i++] = c; + str[i] = 0; + } else + putchar(BELL); + } + refresh(); + } + + if (use_def) + return GS_DEFAULT; + else + return i; +} + +void clear_warning(void) +{ + int i; + + if (!warning_last_time) + return; + + move(WARNING_START,0); + for (i = 0; i < COLS; i++) + addch(' '); + + warning_last_time = FALSE; +} + +void print_warning(char *s) +{ + mvaddstr(WARNING_START, (COLS-strlen(s))/2, s); + putchar(BELL); /* CTRL-G */ + + warning_last_time = TRUE; +} + +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(); + + (void)getch(); + + signal(SIGINT, old_SIGINT); + signal(SIGTERM, old_SIGTERM); + mvcur(0, COLS-1, LINES-1, 0); + nl(); + endwin(); + fdexit(1); +} + +void read_sector(char *buffer, int sect_num) +{ + if (ext2_llseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0) + fatal(BAD_SEEK); + if (read(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) + fatal(BAD_READ); +} + +void write_sector(char *buffer, int sect_num) +{ + if (ext2_llseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0) + fatal(BAD_SEEK); + if (write(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) + fatal(BAD_WRITE); +} + +void check_part_info(void) +{ + int i, pri = 0, log = 0; + + 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) + if (log > 0) + pri++; + else { + ext_info.first_sector = 0; + ext_info.last_sector = 0; + ext_info.offset = 0; + ext_info.flags = 0; + ext_info.id = FREE_SPACE; + ext_info.num = PRIMARY; + } + + 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 (p_info[i].first_sector >= ext_info.first_sector && + p_info[i].last_sector <= ext_info.last_sector) { + p_info[i].id = FREE_SPACE; + p_info[i].num = LOGICAL; + } else if (i > 0 && + p_info[i-1].first_sector >= + ext_info.first_sector && + p_info[i-1].last_sector <= + ext_info.last_sector) { + p_info[i].id = FREE_SPACE; + p_info[i].num = LOGICAL; + } else if (i < num_parts-1 && + p_info[i+1].first_sector >= + ext_info.first_sector && + p_info[i+1].last_sector <= + ext_info.last_sector) { + p_info[i].id = FREE_SPACE; + p_info[i].num = LOGICAL; + } else + p_info[i].id = UNUSABLE; + else /* if (ext_info.id != EXTENDED) */ + p_info[i].id = UNUSABLE; + else /* if (p_info[i].id > 0) */ + while (0); /* Leave these alone */ + 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 (p_info[i].first_sector >= ext_info.first_sector && + p_info[i].last_sector <= ext_info.last_sector) + p_info[i].num = LOGICAL; + else if (i > 0 && + p_info[i-1].first_sector >= + ext_info.first_sector && + p_info[i-1].last_sector <= + ext_info.last_sector) + p_info[i].num = PRI_OR_LOG; + else if (i < num_parts-1 && + p_info[i+1].first_sector >= + ext_info.first_sector && + p_info[i+1].last_sector <= + ext_info.last_sector) + p_info[i].num = PRI_OR_LOG; + else + p_info[i].num = PRIMARY; + else /* if (ext_info.id != EXTENDED) */ + p_info[i].num = PRI_OR_LOG; + else /* if (p_info[i].id > 0) */ + while (0); /* Leave these alone */ + } +} + +void remove_part(int i) +{ + int p; + + for (p = i; p < num_parts; p++) + p_info[p] = p_info[p+1]; + + num_parts--; +} + +void insert_part(int i, int num, int id, int flags, int first, int last, + int offset) +{ + int p; + + for (p = num_parts; p > i; p--) + p_info[p] = p_info[p-1]; + + 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; + + num_parts++; +} + +void del_part(int i) +{ + int num = p_info[i].num; + + if (i > 0 && (p_info[i-1].id == FREE_SPACE || + p_info[i-1].id == UNUSABLE)) { + /* Merge with previous partition */ + p_info[i-1].last_sector = p_info[i].last_sector; + remove_part(i--); + } + + if (i < num_parts - 1 && (p_info[i+1].id == FREE_SPACE || + p_info[i+1].id == UNUSABLE)) { + /* Merge with next partition */ + p_info[i+1].first_sector = p_info[i].first_sector; + remove_part(i); + } + + if (i > 0) + p_info[i].first_sector = p_info[i-1].last_sector + 1; + else + p_info[i].first_sector = 0; + + if (i < num_parts - 1) + p_info[i].last_sector = p_info[i+1].first_sector - 1; + else + p_info[i].last_sector = sectors*heads*cylinders - 1; + + p_info[i].offset = 0; + p_info[i].flags = 0; + p_info[i].id = FREE_SPACE; + p_info[i].num = PRI_OR_LOG; + + if (IS_LOGICAL(num)) { + /* We have a logical partition --> shrink the extended partition + * if (1) this is the first logical drive, or (2) this is the + * 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))) + ext_info.first_sector = p_info[i].last_sector + 1; + 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; + for (i = 0; i < num_parts; i++) + if (p_info[i].num > num) + p_info[i].num--; + } + + /* Clean up the rest of the partitions */ + check_part_info(); +} + +int add_part(int num, int id, int flags, int first, int last, int offset) +{ + int i, pri = 0, log = 0; + + if (num_parts == MAXIMUM_PARTS || + first < 0 || + first >= cylinders*heads*sectors || + last < 0 || + last >= cylinders*heads*sectors) + return -1; + + 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) + pri++; + + if (IS_PRIMARY(num)) + if (pri >= 4) + return -1; + else + pri++; + + for (i = 0; p_info[i].last_sector < first; i++); + + if (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; + 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.num = num; + + return 0; + } else + return -1; + + if (IS_LOGICAL(num)) { + if (ext_info.id != EXTENDED) { + print_warning("!!!! Internal error creating logical " + "drive with no extended partition !!!!"); + } else { + /* We might have a logical partition outside of the extended + * partition's range --> we have to extend the extended + * partition's range to encompass this new partition, but we + * must make sure that there are no primary partitions between + * it and the closest logical drive in extended partition. + */ + if (first < ext_info.first_sector) { + if (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num)) { + print_warning(TWO_EXTENDEDS); + return -1; + } else { + if (first == 0) { + ext_info.first_sector = 0; + ext_info.offset = first = offset; + } 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 + 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); + 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); + + 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; + + check_part_info(); + + return 0; +} + +int find_primary(void) +{ + int num = 0, cur = 0; + + 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)) { + num++; + cur = 0; + } else + cur++; + + if (!IS_PRIMARY(num)) + return -1; + else + return num; +} + +int find_logical(int i) +{ + int num = -1; + int j; + + for (j = i; j < num_parts && num == -1; j++) + if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num)) + num = p_info[j].num; + + if (num == -1) { + num = 4; + for (j = 0; j < num_parts; j++) + if (p_info[j].id > 0 && p_info[j].num == num) + num++; + } + + return num; +} + +void inc_logical(int i) +{ + int j; + + for (j = i; j < num_parts; j++) + if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num)) + p_info[j].num++; +} + +void new_part(int i) +{ + char response[LINE_LENGTH], def[LINE_LENGTH]; + char c; + int first = p_info[i].first_sector; + int last = p_info[i].last_sector; + int offset = 0; + int flags = 0; + int id = LINUX; + int num = -1; + int num_sects = last - first + 1; + int len, ext, j; + + if (p_info[i].num == PRI_OR_LOG) { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Primary or logical [pl]: "); + clrtoeol(); + refresh(); + while (toupper(c = getch()) != 'P' && toupper(c) != 'L' && c != ESC); + if (toupper(c) == 'P') + num = find_primary(); + else if (toupper(c) == 'L') + num = find_logical(i); + else + return; + } else if (p_info[i].num == PRIMARY) + num = find_primary(); + else if (p_info[i].num == LOGICAL) + num = find_logical(i); + else + print_warning("!!! Internal error !!!"); + + sprintf(def, "%.2f", ceiling(num_sects/20.48)/100); + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Size (in MB): "); + if ((len = get_string(response, LINE_LENGTH, def)) <= 0 && + len != GS_DEFAULT) + return; + else if (len > 0) { +#define num_cyls(bytes) (round_int(bytes/SECTOR_SIZE/(sectors*heads))) + for (j = 0; + j < len-1 && (isdigit(response[j]) || response[j] == '.'); + j++); + if (toupper(response[j]) == 'K') { + num_sects = num_cyls(atof(response)*1024)*sectors*heads; + } else if (toupper(response[j]) == 'M') { + num_sects = num_cyls(atof(response)*1024*1024)*sectors*heads; + } else if (toupper(response[j]) == 'C') { + num_sects = round_int(atof(response))*sectors*heads; + } else if (toupper(response[j]) == 'S') { + num_sects = round_int(atof(response)); + } else { + num_sects = num_cyls(atof(response)*1024*1024)*sectors*heads; + } + } + + if (num_sects <= 0 || + num_sects > p_info[i].last_sector - p_info[i].first_sector + 1) + return; + + if (num_sects < p_info[i].last_sector - p_info[i].first_sector + 1) { + /* Determine where inside free space to put partition. + */ + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Add partition at beginning or end of free space [be]: "); + clrtoeol(); + refresh(); + while (toupper(c = getch()) != 'B' && toupper(c) != 'E' && c != ESC); + if (toupper(c) == 'B') + last = first + num_sects - 1; + else if (toupper(c) == 'E') + first = last - num_sects + 1; + else + return; + } + + if (IS_LOGICAL(num) && ext_info.id != EXTENDED) { + /* We want to add a logical partition, but need to create an + * extended partition first. + */ + if ((ext = find_primary()) < 0) { + print_warning(NEED_EXT); + return; + } + (void)add_part(ext, EXTENDED, 0, first, last, + (first == 0 ? sectors : 0)); + } + + if (IS_LOGICAL(num)) + inc_logical(i); + + /* Now we have a complete partition to ourselves */ + if (first == 0 || IS_LOGICAL(num)) + offset = sectors; + + (void)add_part(num, id, flags, first, last, offset); +} + +void clear_p_info(void) +{ + num_parts = 1; + p_info[0].first_sector = 0; + p_info[0].last_sector = sectors*heads*cylinders - 1; + p_info[0].offset = 0; + p_info[0].flags = 0; + p_info[0].id = FREE_SPACE; + p_info[0].num = PRI_OR_LOG; + + ext_info.first_sector = 0; + ext_info.last_sector = 0; + ext_info.offset = 0; + ext_info.flags = 0; + ext_info.id = FREE_SPACE; + ext_info.num = PRIMARY; +} + +void fill_p_info(void) +{ + int p, i; + struct hd_geometry geometry; + 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); + read_sector(buffer.c.b, 0); + + if (!ioctl(fd, HDIO_GETGEO, &geometry)) { + if (!heads) + heads = geometry.heads; + if (!sectors) + sectors = geometry.sectors; + if (!cylinders) + cylinders = geometry.cylinders; + } + + if (!heads || !sectors || !cylinders) + fatal(BAD_GEOMETRY); + + clear_p_info(); + + if (!zero_table) { + for (i = 0; i < 4; i++) { + 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), + 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))) { + fatal(BAD_PRIMARY); + } + if (buffer.p.part[i].sys_ind == EXTENDED) + tmp_ext = ext_info; + } + + if (tmp_ext.id == EXTENDED) { + ext_info = tmp_ext; + logical_sectors[logical] = ext_info.first_sector; + 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); + p++); + if (p > 3) + fatal(BAD_LOGICAL); + + if (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)) { + fatal(BAD_LOGICAL); + } + + for (p = 0; + p < 4 && buffer.p.part[p].sys_ind != 5; + p++); + if (p < 4) { + logical_sectors[logical] = + ext_info.first_sector + buffer.p.part[p].start_sect; + read_sector(buffer.c.b, logical_sectors[logical++]); + } + } while (p < 4 && logical < MAXIMUM_PARTS-4); + } + } +} + +void fill_part_table(struct partition *p, partition_info *pi) +{ + int sects; + + p->boot_ind = pi->flags; + p->sys_ind = pi->id; + if (IS_LOGICAL(pi->num)) + p->start_sect = pi->offset; + else + p->start_sect = pi->first_sector + pi->offset; + p->nr_sects = pi->last_sector - (pi->first_sector+pi->offset) + 1; + sects = (((pi->first_sector+pi->offset)/(sectors*heads) > 1023) ? + heads*sectors*1024 - 1 : pi->first_sector+pi->offset); + set_hsc(p->head, p->sector, p->cyl, sects); + sects = ((pi->last_sector/(sectors*heads) > 1023) ? + heads*sectors*1024 - 1 : pi->last_sector); + set_hsc(p->end_head, p->end_sector, p->end_cyl, sects); +} + +void fill_primary_table(partition_table *buffer) +{ + int i; + + /* Zero out existing table */ + for (i = 0x1BE; i < SECTOR_SIZE; i++) + buffer->c.b[i] = 0; + + for (i = 0; i < num_parts; i++) + 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) + fill_part_table(&(buffer->p.part[ext_info.num]), &ext_info); + + buffer->p.flag = PART_TABLE_FLAG; +} + +void fill_logical_table(partition_table *buffer, partition_info *pi) +{ + struct partition *p; + int i, sects; + + for (i = 0; i < logical && pi->first_sector != logical_sectors[i]; i++); + if (i == logical || buffer->p.flag != (unsigned short)PART_TABLE_FLAG) + for (i = 0; i < SECTOR_SIZE; i++) + buffer->c.b[i] = 0; + + /* Zero out existing table */ + for (i = 0x1BE; i < SECTOR_SIZE; i++) + buffer->c.b[i] = 0; + + fill_part_table(&(buffer->p.part[0]), pi); + + for (i = 0; + i < num_parts && pi->num != p_info[i].num - 1; + i++); + + if (i < num_parts) { + p = &(buffer->p.part[1]); + pi = &(p_info[i]); + + p->boot_ind = 0; + p->sys_ind = 5; + p->start_sect = pi->first_sector - ext_info.first_sector; + p->nr_sects = pi->last_sector - pi->first_sector + 1; + sects = ((pi->first_sector/(sectors*heads) > 1023) ? + heads*sectors*1024 - 1 : pi->first_sector); + set_hsc(p->head, p->sector, p->cyl, sects); + sects = ((pi->last_sector/(sectors*heads) > 1023) ? + heads*sectors*1024 - 1 : pi->last_sector); + set_hsc(p->end_head, p->end_sector, p->end_cyl, sects); + } + + buffer->p.flag = PART_TABLE_FLAG; +} + +void write_part_table(void) +{ + int i, done = FALSE, len; + partition_table buffer; + 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 (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(); + + 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); +} + +void fp_printf(FILE *fp, char *format, ...) +{ + va_list args; + char buf[1024]; + int y, x; + + va_start(args, format); + vsprintf(buf, format, args); + va_end(args); + + if (fp == NULL) { + /* The following works best if the string to be printed has at + most only one newline. */ + printw("%s", buf); + getyx(stdscr, y, x); + if (y >= COMMAND_LINE_Y-2) { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Press any key to continue..."); + clrtoeol(); + refresh(); + (void)getch(); + erase(); + move(0, 0); + } + } else + fprintf(fp, "%s", buf); +} + +#define MAX_PER_LINE 16 +void print_file_buffer(FILE *fp, char *buffer) +{ + int i,l; + + for (i = 0, l = 0; i < SECTOR_SIZE; i++, l++) { + if (l == 0) + fp_printf(fp, "0x%03X:", i); + fp_printf(fp, " %02X", (unsigned char) buffer[i]); + if (l == MAX_PER_LINE - 1) { + fp_printf(fp, "\n"); + l = -1; + } + } + if (l > 0) + fp_printf(fp, "\n"); + fp_printf(fp, "\n"); +} + +void print_raw_table(void) +{ + int i, to_file; + partition_table buffer; + char fname[LINE_LENGTH]; + FILE *fp; + + if (print_only) { + fp = stdout; + to_file = TRUE; + } else { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter filename or press RETURN to display on screen: "); + + if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) + return; + + if (to_file) { + if ((fp = fopen(fname, "w")) == NULL) { + char errstr[LINE_LENGTH]; + sprintf(errstr, PRINT_OPEN_ERR, fname); + print_warning(errstr); + return; + } + } else { + fp = NULL; + erase(); + move(0, 0); + } + } + + fp_printf(fp, "Disk Drive: %s\n", disk_device); + + 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)) { + read_sector(buffer.c.b, p_info[i].first_sector); + fill_logical_table(&buffer, &(p_info[i])); + print_file_buffer(fp, buffer.c.b); + } + + if (to_file) { + if (!print_only) + fclose(fp); + } else { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Press any key to continue..."); + clrtoeol(); + refresh(); + (void)getch(); + } +} + +void print_p_info_entry(FILE *fp, partition_info *p) +{ + int size; + char part_str[21]; + + if (p->id == UNUSABLE) + fp_printf(fp, " None "); + else if (p->id == FREE_SPACE && p->num == PRI_OR_LOG) + fp_printf(fp, " Pri/Log"); + else if (p->id == FREE_SPACE && p->num == PRIMARY) + fp_printf(fp, " Primary"); + else if (p->id == FREE_SPACE && p->num == LOGICAL) + fp_printf(fp, " Logical"); + else + fp_printf(fp, "%2d %-7.7s", p->num+1, + IS_LOGICAL(p->num) ? "Logical" : "Primary"); + + fp_printf(fp, " "); + + fp_printf(fp, "%7d%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, + (((p->last_sector+1)/(sectors*heads)) != + ((float)(p->last_sector+1)/(sectors*heads)) ? + '*' : ' ')); + + fp_printf(fp, " "); + + fp_printf(fp, "%6d%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, + ((size/(sectors*heads)) != ((float)size/(sectors*heads)) ? + '*' : ' ')); + + fp_printf(fp, " "); + + if (p->id == UNUSABLE) + sprintf(part_str, "%.16s", "Unusable"); + else if (p->id == FREE_SPACE) + sprintf(part_str, "%.16s", "Free Space"); + else if (partition_type[p->id]) + sprintf(part_str, "%.16s (%02X)", partition_type[p->id], p->id); + else + sprintf(part_str, "%.16s (%02X)", "Unknown", p->id); + fp_printf(fp, "%-21.21s", part_str); + + fp_printf(fp, " "); + + if (p->flags == ACTIVE_FLAG) + fp_printf(fp, "Boot (%02X)", p->flags); + else if (p->flags != 0) + fp_printf(fp, "Unknown (%02X)", p->flags); + else + fp_printf(fp, "None (%02X)", p->flags); + + fp_printf(fp, "\n"); +} + +void print_p_info(void) +{ + char fname[LINE_LENGTH]; + FILE *fp; + int i, to_file, pext = (ext_info.id == EXTENDED); + + if (print_only) { + fp = stdout; + to_file = TRUE; + } else { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter filename or press RETURN to display on screen: "); + + if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) + return; + + if (to_file) { + if ((fp = fopen(fname, "w")) == NULL) { + char errstr[LINE_LENGTH]; + sprintf(errstr, PRINT_OPEN_ERR, fname); + print_warning(errstr); + return; + } + } else { + fp = NULL; + erase(); + move(0, 0); + } + } + + 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"); + + for (i = 0; i < num_parts; i++) { + if (pext && (p_info[i].first_sector >= ext_info.first_sector)) { + print_p_info_entry(fp,&ext_info); + pext = FALSE; + } + print_p_info_entry(fp, &(p_info[i])); + } + + if (to_file) { + if (!print_only) + fclose(fp); + } else { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Press any key to continue..."); + clrtoeol(); + refresh(); + (void)getch(); + } +} + +void print_part_entry(FILE *fp, int num, partition_info *pi) +{ + int first = 0, start = 0, end = 0, size = 0; + int ss = 0, sh = 0, sc = 0; + int es = 0, eh = 0, ec = 0; + int flags = 0, id = 0; + + if (pi != NULL) { + flags = pi->flags; + id = pi->id; + + if (IS_LOGICAL(num)) + first = pi->offset; + else + first = pi->first_sector + pi->offset; + + start = pi->first_sector + pi->offset; + end = pi->last_sector; + size = end - start + 1; + if ((start/(sectors*heads)) > 1023) + start = heads*sectors*1024 - 1; + if ((end/(sectors*heads)) > 1023) + end = heads*sectors*1024 - 1; + + ss = start % sectors + 1; + start /= sectors; + sh = start % heads; + sc = start / heads; + + es = end % sectors + 1; + end /= sectors; + eh = end % heads; + ec = end / heads; + } + + fp_printf(fp, "%2d 0x%02X %4d %4d %4d 0x%02X %4d %4d %4d %7d %7d\n", + num+1, flags, sh, ss, sc, id, eh, es, ec, first, size); +} + + +void print_part_table(void) +{ + int i, j, to_file; + char fname[LINE_LENGTH]; + FILE *fp; + + if (print_only) { + fp = stdout; + to_file = TRUE; + } else { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter filename or press RETURN to display on screen: "); + + if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) + return; + + if (to_file) { + if ((fp = fopen(fname, "w")) == NULL) { + char errstr[LINE_LENGTH]; + sprintf(errstr, PRINT_OPEN_ERR, fname); + print_warning(errstr); + return; + } + } else { + fp = NULL; + erase(); + move(0, 0); + } + } + + 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"); + + for (i = 0; i < 4; i++) { + for (j = 0; + j < num_parts && (p_info[j].id <= 0 || p_info[j].num != i); + j++); + if (j < num_parts) { + print_part_entry(fp, i, &(p_info[j])); + } else if (ext_info.id == EXTENDED && ext_info.num == i) { + print_part_entry(fp, i, &ext_info); + } else { + print_part_entry(fp, i, NULL); + } + } + + for (i = 0; i < num_parts; i++) + if (IS_LOGICAL(p_info[i].num)) + print_part_entry(fp, p_info[i].num, &(p_info[i])); + + if (to_file) { + if (!print_only) + fclose(fp); + } else { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Press any key to continue..."); + clrtoeol(); + refresh(); + (void)getch(); + } +} + +void print_tables(void) +{ + int done = FALSE; + + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Print format [rst]: "); + clrtoeol(); + refresh(); + + while (!done) + switch (toupper(getch())) { + case 'R': + print_raw_table(); + done = TRUE; + break; + case 'S': + print_p_info(); + done = TRUE; + break; + case 'T': + print_part_table(); + done = TRUE; + break; + case ESC: + done = TRUE; + break; + } +} + +#define END_OF_HELP "EOHS!" +#define NEW_HELP_SCREEN "SNHS!" +void display_help() +{ + char *help_text[] = { + "Help Screen for cfdisk " VERSION, + "", + "This is cfdisk, a curses based disk partitioning programs, which", + "allows you to create, delete and modify partitions on your hard", + "disk drive.", + "", + "Copyright (C) 1994 Kevin E. Martin", + "", + "Command Meaning", + "------- -------", + " b Toggle bootable flag of the current partition", + " d Delete the current partition", + " g Change cylinders, heads, sectors-per-track parameters", + " WARNING: This option should only be used by people who", + " know what they are doing.", + " h Print this screen", + " m Maximize disk usage of the current partition", + " Note: This may make the partition incompatible with", + " DOS, OS/2, ...", + " n Create new partition from free space", + " p Print partition table to the screen or to a file", + " There are several different formats for the partition", + " that you can choose from:", + " r - Raw data (exactly what would be written to disk)", + " s - Table ordered by sectors", + " t - Table in raw format", + " q Quit program without writing partition table", + " t Change the filesystem type", + " u Change units of the partition size display", + " Rotates through Mb, sectors and cylinders", + " W Write partition table to disk (must enter upper case W)", + " Since this might destroy data on the disk, you must", + " either confirm or deny the write by entering `yes' or", + " `no'", + "Up Arrow Move cursor to the previous partition", + "Down Arrow Move cursor to the next partition", + "CTRL-L Redraws the screen", + " ? Print this screen", + "", + "Note: All of the commands can be entered with either upper or lower", + "case letters (except for Writes).", + END_OF_HELP + }; + + int cur_line = 0; + FILE *fp = NULL; + + erase(); + move(0, 0); + while (strcmp(help_text[cur_line], END_OF_HELP)) + if (!strcmp(help_text[cur_line], NEW_HELP_SCREEN)) { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Press any key to continue..."); + clrtoeol(); + refresh(); + (void)getch(); + erase(); + move(0, 0); + cur_line++; + } else + fp_printf(fp, "%s\n", help_text[cur_line++]); + + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Press any key to continue..."); + clrtoeol(); + refresh(); + (void)getch(); +} + +int change_geometry(void) +{ + int ret_val = FALSE; + int done = FALSE; + char def[LINE_LENGTH]; + char response[LINE_LENGTH]; + int tmp_val; + + while (!done) { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Change disk geometry information [chs]: "); + clrtoeol(); + refresh(); + + clear_warning(); + + switch (toupper(getch())) { + case 'C': + sprintf(def, "%d", cylinders); + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter the number of cylinders: "); + if (get_string(response, LINE_LENGTH, def) > 0) { + tmp_val = atoi(response); + if (tmp_val > 0 && tmp_val <= MAX_CYLINDERS) { + cylinders = tmp_val; + ret_val = TRUE; + } else + print_warning(BAD_CYLINDERS); + } + break; + case 'H': + sprintf(def, "%d", heads); + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter the number of heads: "); + if (get_string(response, LINE_LENGTH, def) > 0) { + tmp_val = atoi(response); + if (tmp_val > 0 && tmp_val <= MAX_HEADS) { + heads = tmp_val; + ret_val = TRUE; + } else + print_warning(BAD_HEADS); + } + break; + case 'S': + sprintf(def, "%d", sectors); + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter the number of sectors per track: "); + if (get_string(response, LINE_LENGTH, def) > 0) { + tmp_val = atoi(response); + if (tmp_val > 0 && tmp_val <= MAX_SECTORS) { + sectors = tmp_val; + ret_val = TRUE; + } else + print_warning(BAD_SECTORS); + } + break; + case ESC: + case CR: + done = TRUE; + break; + default: + putchar(BELL); + break; + } + } + + 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) { + if (p_info[num_parts-1].id == FREE_SPACE || + p_info[num_parts-1].id == UNUSABLE) + remove_part(num_parts-1); + else + del_part(num_parts-1); + } + + p_info[num_parts-1].last_sector = heads*sectors*cylinders - 1; + + 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 (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; + } else { + insert_part(num_parts, PRI_OR_LOG, FREE_SPACE, 0, + p_info[num_parts-1].last_sector+1, + heads*sectors*cylinders-1, 0); + } + } + + /* Make sure the partitions are correct */ + check_part_info(); + } + + return ret_val; +} + +void change_id(int i) +{ + char id[LINE_LENGTH], def[LINE_LENGTH]; + int num_types = 0; + int num_across, num_down; + int len, new_id = LINUX; + int y_start, y_end; + int j, pos; + + for (num_types = 0, j = 1; j < NUM_PART_TYPES; j++) + if (partition_type[j]) + num_types++; + + num_across = COLS/COL_ID_WIDTH; + num_down = (((float)num_types)/num_across + 1); + y_start = COMMAND_LINE_Y - 1 - num_down; + if (y_start > DISK_TABLE_START+cur_part+4) + y_start = DISK_TABLE_START+cur_part+4; + y_end = y_start + num_down - 1; + + for (j = y_start - 1; j <= y_end + 1; j++) { + move(j, 0); + clrtoeol(); + } + + for (pos = 0, j = 1; j < NUM_PART_TYPES; j++) + if (partition_type[j]) { + move(y_start + pos % num_down, (pos/num_down)*COL_ID_WIDTH + 1); + printw("%02X %-16.16s", j, partition_type[j]); + pos++; + } + + sprintf(def, "%02X", new_id); + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Enter filesystem type: "); + if ((len = get_string(id, 2, def)) <= 0 && len != GS_DEFAULT) + return; + + if (len != GS_DEFAULT) { + if (!isxdigit(id[0])) + return; + new_id = (isdigit(id[0]) ? id[0] - '0' : tolower(id[0]) - 'a' + 10); + if (len == 2) + if (isxdigit(id[1])) + new_id = new_id*16 + + (isdigit(id[1]) ? id[1] - '0' : tolower(id[1]) - 'a' + 10); + else + return; + } + + if (new_id == 0) + print_warning(ID_EMPTY); + else if (new_id == EXTENDED) + print_warning(ID_EXT); + else + p_info[i].id = new_id; +} + +void draw_partition(int i) +{ + int size, j; + int y = i + DISK_TABLE_START + 2 - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN; + + if (!arrow_cursor) { + move(y, 0); + for (j = 0; j < COLS; j++) + addch(' '); + } + + if (p_info[i].id > 0) { + mvprintw(y, NAME_START, + "%s%d", disk_device, p_info[i].num+1); + if (p_info[i].flags) { + if (p_info[i].flags == ACTIVE_FLAG) + mvaddstr(y, FLAGS_START, "Boot"); + else + mvprintw(y, FLAGS_START, "Unk(%02X)", p_info[i].flags); + if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) { + if (p_info[i].offset != sectors) + addstr(", NC"); + } else { + if (p_info[i].offset != 0) + addstr(", NC"); + } + } else { + if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) { + if (p_info[i].offset != sectors) + mvaddstr(y, FLAGS_START, "NC"); + } else { + if (p_info[i].offset != 0) + mvaddstr(y, FLAGS_START, "NC"); + } + } + } + mvaddstr(y, PTYPE_START, + (p_info[i].id == UNUSABLE ? "" : + (IS_LOGICAL(p_info[i].num) ? "Logical" : + (p_info[i].num >= 0 ? "Primary" : + (p_info[i].num == PRI_OR_LOG ? "Pri/Log" : + (p_info[i].num == PRIMARY ? "Primary" : "Logical")))))); + if (p_info[i].id == UNUSABLE) + mvaddstr(y, FSTYPE_START, "Unusable"); + else if (p_info[i].id == FREE_SPACE) + mvaddstr(y, FSTYPE_START, "Free Space"); + else if (partition_type[p_info[i].id]) + mvaddstr(y, FSTYPE_START, partition_type[p_info[i].id]); + else + mvprintw(y, FSTYPE_START, "Unknown (%02X)", p_info[i].id); + + size = p_info[i].last_sector - p_info[i].first_sector + 1; + if (display_units == SECTORS) + mvprintw(y, SIZE_START, "%9d", size); + else if (display_units == CYLINDERS) + mvprintw(y, SIZE_START, "%9d", size/(sectors*heads)); + else + mvprintw(y, SIZE_START, "%9.2f", ceiling(size/20.48)/100); + if (((size/(sectors*heads)) != ceiling(size/(sectors*(float)heads))) || + ((p_info[i].first_sector/(sectors*heads)) != + ceiling(p_info[i].first_sector/(sectors*heads)))) + mvprintw(y, COLUMNS-1, "*"); +} + +void init_const(void) +{ + if (!defined) { + NAME_START = (((float)NAME_START)/COLUMNS)*COLS; + FLAGS_START = (((float)FLAGS_START)/COLUMNS)*COLS; + PTYPE_START = (((float)PTYPE_START)/COLUMNS)*COLS; + FSTYPE_START = (((float)FSTYPE_START)/COLUMNS)*COLS; + SIZE_START = (((float)SIZE_START)/COLUMNS)*COLS; + COMMAND_LINE_X = (((float)COMMAND_LINE_X)/COLUMNS)*COLS; + + COMMAND_LINE_Y = LINES - 4; + WARNING_START = LINES - 2; + + if ((NUM_ON_SCREEN = COMMAND_LINE_Y - DISK_TABLE_START - 3) <= 0) + NUM_ON_SCREEN = 1; + + COLUMNS = COLS; + defined = TRUE; + } +} + +void draw_screen(void) +{ + int i; + char *line; + + line = (char *)malloc((COLS+1)*sizeof(char)); + + if (warning_last_time) { + for (i = 0; i < COLS; i++) { + move(WARNING_START, i); + line[i] = inch(); + } + line[COLS] = 0; + } + + erase(); + + if (warning_last_time) + mvaddstr(WARNING_START, 0, line); + + + sprintf(line, "cfdisk %s", VERSION); + mvaddstr(HEADER_START, (COLS-strlen(line))/2, line); + sprintf(line, "Disk Drive: %s", disk_device); + mvaddstr(HEADER_START+2, (COLS-strlen(line))/2, line); + sprintf(line, "Heads: %d Sectors per Track: %d Cylinders: %d", + heads, sectors, cylinders); + mvaddstr(HEADER_START+3, (COLS-strlen(line))/2, line); + + mvaddstr(DISK_TABLE_START, NAME_START, "Name"); + mvaddstr(DISK_TABLE_START, FLAGS_START, "Flags"); + mvaddstr(DISK_TABLE_START, PTYPE_START, "Part Type"); + mvaddstr(DISK_TABLE_START, FSTYPE_START, "FS Type"); + if (display_units == SECTORS) + mvaddstr(DISK_TABLE_START, SIZE_START, " Sectors"); + else if (display_units == CYLINDERS) + mvaddstr(DISK_TABLE_START, SIZE_START, "Cylinders"); + else + mvaddstr(DISK_TABLE_START, SIZE_START, "Size (MB)"); + + move(DISK_TABLE_START+1, 1); + for (i = 1; i < COLS-1; i++) + addch('-'); + + if (NUM_ON_SCREEN >= num_parts) + for (i = 0; i < num_parts; i++) + draw_partition(i); + else + for (i = (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN; + i < NUM_ON_SCREEN + (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN && + i < num_parts; + i++) + draw_partition(i); + + free(line); +} + +int draw_cursor(int move) +{ + if (move != 0 && (cur_part + move < 0 || cur_part + move >= num_parts)) + return -1; + + if (arrow_cursor) + mvaddstr(DISK_TABLE_START + cur_part + 2 + - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, " "); + else + draw_partition(cur_part); + + cur_part += move; + + if (((cur_part - move)/NUM_ON_SCREEN)*NUM_ON_SCREEN != + (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN) + draw_screen(); + + if (arrow_cursor) + mvaddstr(DISK_TABLE_START + cur_part + 2 + - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, "-->"); + else { + standout(); + draw_partition(cur_part); + standend(); + } + + 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; + char command; + + initscr(); + old_SIGINT = signal(SIGINT, die); + old_SIGTERM = signal(SIGTERM, die); +#ifdef DEBUG + signal(SIGINT, old_SIGINT); + signal(SIGTERM, old_SIGTERM); +#endif + + cbreak(); + noecho(); + nonl(); + + init_const(); + + fill_p_info(); + + draw_screen(); + + while (!done) { + (void)draw_cursor(0); + + if (p_info[cur_part].id == FREE_SPACE) + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Command [hnpquW?]: "); + else if (p_info[cur_part].id > 0) + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Command [bdhmpqtuW?]: "); + else + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Command [hpquW?]: "); + + clrtoeol(); + refresh(); + + clear_warning(); + + switch (command = getch()) { + case 'B': + case 'b': + if (p_info[cur_part].id > 0) + p_info[cur_part].flags ^= 0x80; + else + print_warning(NO_FLAGS); + break; + case 'D': + case 'd': + if (p_info[cur_part].id > 0) { + del_part(cur_part); + if (cur_part >= num_parts) + cur_part = num_parts - 1; + draw_screen(); + } else + print_warning(DEL_EMPTY); + break; + case 'G': + case 'g': + if (change_geometry()) + draw_screen(); + break; + case 'M': + case 'm': + if (p_info[cur_part].id > 0) { + if (p_info[cur_part].first_sector == 0 || + IS_LOGICAL(p_info[cur_part].num)) { + if (p_info[cur_part].offset == sectors) + p_info[cur_part].offset = 1; + else + p_info[cur_part].offset = sectors; + draw_screen(); + } else if (p_info[cur_part].offset != 0) + p_info[cur_part].offset = 0; + else + print_warning(MAX_UNMAXABLE); + } else + print_warning(MAX_UNMAXABLE); + break; + case 'N': + case 'n': + if (p_info[cur_part].id == FREE_SPACE) { + new_part(cur_part); + draw_screen(); + } else if (p_info[cur_part].id == UNUSABLE) + print_warning(ADD_UNUSABLE); + else + print_warning(ADD_EXISTS); + break; + case 'P': + case 'p': + print_tables(); + draw_screen(); + break; + case 'Q': + case 'q': + done = TRUE; + break; + case 'T': + case 't': + if (p_info[cur_part].id > 0) { + change_id(cur_part); + draw_screen(); + } else + print_warning(TYPE_EMPTY); + break; + case 'U': + case 'u': + if (display_units == MEGABYTES) + display_units = SECTORS; + else if (display_units == SECTORS) + display_units = CYLINDERS; + else if (display_units == CYLINDERS) + display_units = MEGABYTES; + draw_screen(); + break; + case 'W': + write_part_table(); + break; + case 'H': + case 'h': + case '?': + display_help(); + draw_screen(); + break; + case ESC: + if ((command = getch()) == '[') { + command = getch(); + switch (command) { + case 'A' : /* Up arrow */ + if (!draw_cursor(-1)) + command = 0; + else + print_warning(NO_MORE_PARTS); + break; + case 'B' : /* Down arrow */ + if (!draw_cursor(1)) + command = 0; + else + print_warning(NO_MORE_PARTS); + break; + case 'C' : /* Right arrow */ + case 'D' : /* Left arrow */ + } + } + if (command) + putchar(BELL); /* CTRL-G */ + break; + case REDRAWKEY: + clear(); + draw_screen(); + break; + default: + print_warning(BAD_COMMAND); + putchar(BELL); /* CTRL-G */ + } + } + + signal(SIGINT, old_SIGINT); + signal(SIGTERM, old_SIGTERM); + mvcur(0, COLS-1, LINES-1, 0); + nl(); + endwin(); + fdexit(0); +} + +void copyright(void) +{ + fprintf(stderr, "Copyright (C) 1994 Kevin E. Martin\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"); + copyright(); +} + +void main(int argc, char **argv) +{ + char c; + int i, len; + + while ((c = getopt(argc, argv, "ac:h:s:vzP:")) != EOF) + switch (c) { + case 'a': + arrow_cursor = TRUE; + break; + case 'c': + cylinders = atoi(optarg); + if (cylinders <= 0 || cylinders > MAX_CYLINDERS) { + fprintf(stderr, "%s: %s\n", argv[0], BAD_CYLINDERS); + exit(1); + } + break; + case 'h': + heads = atoi(optarg); + if (heads <= 0 || heads > MAX_HEADS) { + fprintf(stderr, "%s: %s\n", argv[0], BAD_HEADS); + exit(1); + } + break; + case 's': + sectors = atoi(optarg); + if (sectors <= 0 || sectors > MAX_SECTORS) { + fprintf(stderr, "%s: %s\n", argv[0], BAD_SECTORS); + exit(1); + } + break; + case 'v': + fprintf(stderr, "cfdisk %s\n", VERSION); + copyright(); + exit(0); + case 'z': + zero_table = TRUE; + break; + case 'P': + len = strlen(optarg); + for (i = 0; i < len; i++) { + switch (optarg[i]) { + case 'r': + print_only |= PRINT_RAW_TABLE; + break; + case 's': + print_only |= PRINT_SECTOR_TABLE; + break; + case 't': + print_only |= PRINT_PARTITION_TABLE; + break; + default: + usage(argv[0]); + break; + } + } + break; + default: + usage(argv[0]); + exit(1); + } + + if (argc-optind == 1) + disk_device = argv[optind]; + else if (argc-optind != 0) { + usage(argv[0]); + exit(1); + } else if ((fd = open(DEFAULT_DEVICE, O_RDWR)) < 0) + disk_device = ALTERNATE_DEVICE; + else close(fd); + + if (print_only) { + fill_p_info(); + if (print_only & PRINT_RAW_TABLE) + print_raw_table(); + if (print_only & PRINT_SECTOR_TABLE) + print_p_info(); + if (print_only & PRINT_PARTITION_TABLE) + print_part_table(); + } else + do_curses_fdisk(); +} diff --git a/disk-utils/cfdisk.c.orig b/disk-utils/cfdisk.c.orig new file mode 100644 index 000000000..3b9f22f58 --- /dev/null +++ b/disk-utils/cfdisk.c.orig @@ -0,0 +1,2066 @@ +/**************************************************************************** + * + * CFDISK + * + * cfdisk is a curses based disk drive partitioning program that can + * create partitions for a wide variety of operating systems including + * Linux, MS-DOS and OS/2. + * + * cfdisk was inspired by the fdisk program, by A. V. Le Blanc + * (LeBlanc@mcc.ac.uk). + * + * Copyright (C) 1994 Kevin E. Martin (martin@cs.unc.edu) + * + * cfdisk 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 2 of the License, or + * (at your option) any later version. + * + * cfdisk is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with cfdisk; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Created: Fri Jan 28 22:46:58 1994, martin@cs.unc.edu + * + ****************************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <unistd.h> +#include <ctype.h> +#include <errno.h> +#include <getopt.h> +#include <fcntl.h> +#include <curses.h> +#include <signal.h> +#include <math.h> +#include <sys/ioctl.h> +#include <linux/genhd.h> +#include <linux/hdreg.h> +#include <linux/fs.h> /* for BLKRRPART */ + +typedef long ext2_loff_t; +extern ext2_loff_t ext2_llseek(unsigned int fd, + ext2_loff_t offset, + unsigned int origin); + +#define VERSION "0.8 BETA (>2GB)" + +#define DEFAULT_DEVICE "/dev/hda" +#define ALTERNATE_DEVICE "/dev/sda" + +#define LINE_LENGTH 80 +#define MAXIMUM_PARTS 60 + +#define SECTOR_SIZE 512 + +#define MAX_CYLINDERS 65535 +#define MAX_HEADS 255 +#define MAX_SECTORS 63 + +#define ACTIVE_FLAG 0x80 +#define PART_TABLE_FLAG 0xAA55 + +#define UNUSABLE -1 +#define FREE_SPACE 0x00 +#define EXTENDED 0x05 +#define LINUX_MINIX 0x81 +#define LINUX_SWAP 0x82 +#define LINUX 0x83 + +#define ADD_EXISTS "This partition is already in use" +#define ADD_UNUSABLE "This partition is unusable" +#define DEL_EMPTY "Cannot delete an empty partition" +#define ID_EMPTY "Cannot change FS Type to empty" +#define ID_EXT "Cannot change FS Type to extended" +#define NEED_EXT "No room to create the extended partition" +#define NO_FLAGS "Cannot make this partition bootable" +#define NO_MORE_PARTS "No more partitions" +#define PRINT_OPEN_ERR "Cannot open file '%s'" +#define TWO_EXTENDEDS "Cannot create logical drive here -- would create two extended partitions" +#define TYPE_EMPTY "Cannot change the type of an empty partition" +#define BAD_COMMAND "Illegal command" +#define MAX_UNMAXABLE "Cannot maximize this partition" +#define BAD_OPEN "Cannot open disk drive" +#define BAD_SEEK "Cannot seek on disk drive" +#define BAD_READ "Cannot read disk drive" +#define BAD_WRITE "Cannot write disk drive" +#define BAD_GEOMETRY "Cannot read disk drive geometry" +#define BAD_PRIMARY "Bad primary partition" +#define BAD_LOGICAL "Bad logical partition" +#define BAD_CYLINDERS "Illegal cylinders value" +#define BAD_HEADS "Illegal heads value" +#define BAD_SECTORS "Illegal sectors value" +#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..." +#define YES_WRITE "Wrote partition table to disk" +#define NO_WRITE "Did not write partition table to disk" +#define RRPART_FAILED "Wrote partition table, but re-read table failed. Reboot to update table." + +#define PRI_OR_LOG -1 +#define PRIMARY -2 +#define LOGICAL -3 + +#define COL_ID_WIDTH 20 + +#define CR '\015' +#define ESC '\033' +#define DEL '\177' +#define BELL '\007' +/* '\014' == ^L */ +#define REDRAWKEY '\014' + +/* Display units */ +#define MEGABYTES 1 +#define SECTORS 2 +#define CYLINDERS 3 + +#define GS_DEFAULT -1 +#define GS_ESCAPE -2 + +#define PRINT_RAW_TABLE 1 +#define PRINT_SECTOR_TABLE 2 +#define PRINT_PARTITION_TABLE 4 + +#define IS_PRIMARY(p) ((p) >= 0 && (p) < 4) +#define IS_LOGICAL(p) ((p) > 3) + +#define round_int(d) ((double)((int)(d+0.5))) +#define ceiling(d) ((double)(((d) != (int)(d)) ? (int)(d+1.0) : (int)(d))) + +#define set_hsc(h,s,c,sector) \ +{ \ + s = sector % sectors + 1; \ + sector /= sectors; \ + h = sector % heads; \ + sector /= heads; \ + c = sector & 0xFF; \ + s |= (sector >> 2) & 0xC0;\ +} + +#define ALIGNMENT 2 +typedef union { + struct { + unsigned char align[ALIGNMENT]; + unsigned char b[SECTOR_SIZE]; + } c; + struct { + unsigned char align[ALIGNMENT]; + unsigned char buffer[0x1BE]; + struct partition part[4]; + unsigned short flag; + } p; +} partition_table; + +typedef struct { + int first_sector; /* first sector in partition */ + int last_sector; /* last sector in partition */ + int offset; /* offset from first sector to start of data */ + int flags; /* active == 0x80 */ + int id; /* filesystem type */ + int num; /* number of partition -- primary vs. logical */ +} partition_info; + +char *disk_device = DEFAULT_DEVICE; +int fd; +int heads = 0; +int sectors = 0; +int cylinders = 0; +int changed = FALSE; +int opened = FALSE; + +partition_info p_info[MAXIMUM_PARTS]; +partition_info ext_info; +int num_parts = 0; + +int logical = 0; +int logical_sectors[MAXIMUM_PARTS]; + +__sighandler_t old_SIGINT, old_SIGTERM; + +int arrow_cursor = FALSE; +int display_units = MEGABYTES; +int zero_table = FALSE; +int print_only = 0; + +/* Curses screen information */ +int cur_part = 0; +int warning_last_time = FALSE; +int defined = FALSE; +int COLUMNS = 80; +int NUM_ON_SCREEN = 1; + +/* Y coordinates */ +int HEADER_START = 0; +int DISK_TABLE_START = 5; +int WARNING_START = 23; +int COMMAND_LINE_Y = 21; + +/* X coordinates */ +int NAME_START = 4; +int FLAGS_START = 16; +int PTYPE_START = 30; +int FSTYPE_START = 45; +int SIZE_START = 70; +int COMMAND_LINE_X = 5; + +#define NUM_PART_TYPES 256 +char *partition_type[NUM_PART_TYPES] = { + [LINUX_MINIX] = "Linux/MINIX", + [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", + [0x0A] = "OS/2 Boot Manager", + [0xA5] = "BSD/386", + +/* The rest of these are taken from A. V. Le Blanc's (LeBlanc@mcc.ac.uk) + * fdisk program. I do not know where they came from, but I include + * them for completeness. + */ + + [0x02] = "XENIX root", + [0x03] = "XENIX usr", + [0x08] = "AIX", + [0x09] = "AIX bootable", + [0x40] = "Venix 80286", + [0x51] = "Novell?", + [0x52] = "Microport", + [0x63] = "GNU HURD", + [0x64] = "Novell", + [0x75] = "PC/IX", + [0x80] = "Old MINIX", + [0x93] = "Amoeba", + [0x94] = "Amoeba BBT", + [0xB7] = "BSDI fs", + [0xB8] = "BSDI swap", + [0xC7] = "Syrinx", + [0xDB] = "CP/M", + [0xE1] = "DOS access", + [0xE3] = "DOS R/O", + [0xF2] = "DOS secondary", + [0xFF] = "BBT" +}; + +void fdexit(int ret) +{ + if (opened) + close(fd); + + if (changed) { + fprintf(stderr, "Disk has been changed.\n"); + fprintf(stderr, "Reboot the system to ensure the partition " + "table is correctly updated.\n"); + + fprintf( stderr, "\nWARNING: If you have created or modified any\n" + "DOS 6.x partitions, please see the cfdisk manual\n" + "page for additional information.\n" ); + } + + + exit(ret); +} + +int get_string(char *str, int len, char *def) +{ + char c; + int i = 0; + int x, y; + int use_def = FALSE; + + getyx(stdscr, y, x); + clrtoeol(); + + str[i] = 0; + + if (def != NULL) { + mvaddstr(y, x, def); + move(y, x); + use_def = TRUE; + } + + refresh(); + while ((c = getch()) != '\n' && c != CR) { + switch (c) { + case ESC: + move(y, x); + clrtoeol(); + refresh(); + return GS_ESCAPE; + case DEL: + case '\b': + if (i > 0) { + str[--i] = 0; + mvaddch(y, x+i, ' '); + move(y, x+i); + } else if (use_def) { + clrtoeol(); + use_def = FALSE; + } else + putchar(BELL); + break; + default: + if (i < len && isprint(c)) { + mvaddch(y, x+i, c); + if (use_def) { + clrtoeol(); + use_def = FALSE; + } + str[i++] = c; + str[i] = 0; + } else + putchar(BELL); + } + refresh(); + } + + if (use_def) + return GS_DEFAULT; + else + return i; +} + +void clear_warning(void) +{ + int i; + + if (!warning_last_time) + return; + + move(WARNING_START,0); + for (i = 0; i < COLS; i++) + addch(' '); + + warning_last_time = FALSE; +} + +void print_warning(char *s) +{ + mvaddstr(WARNING_START, (COLS-strlen(s))/2, s); + putchar(BELL); /* CTRL-G */ + + warning_last_time = TRUE; +} + +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(); + + (void)getch(); + + signal(SIGINT, old_SIGINT); + signal(SIGTERM, old_SIGTERM); + mvcur(0, COLS-1, LINES-1, 0); + nl(); + endwin(); + fdexit(1); +} + +void read_sector(char *buffer, int sect_num) +{ + if (ext2_llseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0) + fatal(BAD_SEEK); + if (read(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) + fatal(BAD_READ); +} + +void write_sector(char *buffer, int sect_num) +{ + if (ext2_llseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0) + fatal(BAD_SEEK); + if (write(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) + fatal(BAD_WRITE); +} + +void check_part_info(void) +{ + int i, pri = 0, log = 0; + + 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) + if (log > 0) + pri++; + else { + ext_info.first_sector = 0; + ext_info.last_sector = 0; + ext_info.offset = 0; + ext_info.flags = 0; + ext_info.id = FREE_SPACE; + ext_info.num = PRIMARY; + } + + 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 (p_info[i].first_sector >= ext_info.first_sector && + p_info[i].last_sector <= ext_info.last_sector) { + p_info[i].id = FREE_SPACE; + p_info[i].num = LOGICAL; + } else if (i > 0 && + p_info[i-1].first_sector >= + ext_info.first_sector && + p_info[i-1].last_sector <= + ext_info.last_sector) { + p_info[i].id = FREE_SPACE; + p_info[i].num = LOGICAL; + } else if (i < num_parts-1 && + p_info[i+1].first_sector >= + ext_info.first_sector && + p_info[i+1].last_sector <= + ext_info.last_sector) { + p_info[i].id = FREE_SPACE; + p_info[i].num = LOGICAL; + } else + p_info[i].id = UNUSABLE; + else /* if (ext_info.id != EXTENDED) */ + p_info[i].id = UNUSABLE; + else /* if (p_info[i].id > 0) */ + while (0); /* Leave these alone */ + 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 (p_info[i].first_sector >= ext_info.first_sector && + p_info[i].last_sector <= ext_info.last_sector) + p_info[i].num = LOGICAL; + else if (i > 0 && + p_info[i-1].first_sector >= + ext_info.first_sector && + p_info[i-1].last_sector <= + ext_info.last_sector) + p_info[i].num = PRI_OR_LOG; + else if (i < num_parts-1 && + p_info[i+1].first_sector >= + ext_info.first_sector && + p_info[i+1].last_sector <= + ext_info.last_sector) + p_info[i].num = PRI_OR_LOG; + else + p_info[i].num = PRIMARY; + else /* if (ext_info.id != EXTENDED) */ + p_info[i].num = PRI_OR_LOG; + else /* if (p_info[i].id > 0) */ + while (0); /* Leave these alone */ + } +} + +void remove_part(int i) +{ + int p; + + for (p = i; p < num_parts; p++) + p_info[p] = p_info[p+1]; + + num_parts--; +} + +void insert_part(int i, int num, int id, int flags, int first, int last, + int offset) +{ + int p; + + for (p = num_parts; p > i; p--) + p_info[p] = p_info[p-1]; + + 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; + + num_parts++; +} + +void del_part(int i) +{ + int num = p_info[i].num; + + if (i > 0 && (p_info[i-1].id == FREE_SPACE || + p_info[i-1].id == UNUSABLE)) { + /* Merge with previous partition */ + p_info[i-1].last_sector = p_info[i].last_sector; + remove_part(i--); + } + + if (i < num_parts - 1 && (p_info[i+1].id == FREE_SPACE || + p_info[i+1].id == UNUSABLE)) { + /* Merge with next partition */ + p_info[i+1].first_sector = p_info[i].first_sector; + remove_part(i); + } + + if (i > 0) + p_info[i].first_sector = p_info[i-1].last_sector + 1; + else + p_info[i].first_sector = 0; + + if (i < num_parts - 1) + p_info[i].last_sector = p_info[i+1].first_sector - 1; + else + p_info[i].last_sector = sectors*heads*cylinders - 1; + + p_info[i].offset = 0; + p_info[i].flags = 0; + p_info[i].id = FREE_SPACE; + p_info[i].num = PRI_OR_LOG; + + if (IS_LOGICAL(num)) { + /* We have a logical partition --> shrink the extended partition + * if (1) this is the first logical drive, or (2) this is the + * 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))) + ext_info.first_sector = p_info[i].last_sector + 1; + 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; + for (i = 0; i < num_parts; i++) + if (p_info[i].num > num) + p_info[i].num--; + } + + /* Clean up the rest of the partitions */ + check_part_info(); +} + +int add_part(int num, int id, int flags, int first, int last, int offset) +{ + int i, pri = 0, log = 0; + + if (num_parts == MAXIMUM_PARTS || + first < 0 || + first >= cylinders*heads*sectors || + last < 0 || + last >= cylinders*heads*sectors) + return -1; + + 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) + pri++; + + if (IS_PRIMARY(num)) + if (pri >= 4) + return -1; + else + pri++; + + for (i = 0; p_info[i].last_sector < first; i++); + + if (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; + 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.num = num; + + return 0; + } else + return -1; + + if (IS_LOGICAL(num)) { + if (ext_info.id != EXTENDED) { + print_warning("!!!! Internal error creating logical " + "drive with no extended partition !!!!"); + } else { + /* We might have a logical partition outside of the extended + * partition's range --> we have to extend the extended + * partition's range to encompass this new partition, but we + * must make sure that there are no primary partitions between + * it and the closest logical drive in extended partition. + */ + if (first < ext_info.first_sector) { + if (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num)) { + print_warning(TWO_EXTENDEDS); + return -1; + } else { + if (first == 0) { + ext_info.first_sector = 0; + ext_info.offset = first = offset; + } 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 + 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); + 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); + + 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; + + check_part_info(); + + return 0; +} + +int find_primary(void) +{ + int num = 0, cur = 0; + + 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)) { + num++; + cur = 0; + } else + cur++; + + if (!IS_PRIMARY(num)) + return -1; + else + return num; +} + +int find_logical(int i) +{ + int num = -1; + int j; + + for (j = i; j < num_parts && num == -1; j++) + if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num)) + num = p_info[j].num; + + if (num == -1) { + num = 4; + for (j = 0; j < num_parts; j++) + if (p_info[j].id > 0 && p_info[j].num == num) + num++; + } + + return num; +} + +void inc_logical(int i) +{ + int j; + + for (j = i; j < num_parts; j++) + if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num)) + p_info[j].num++; +} + +void new_part(int i) +{ + char response[LINE_LENGTH], def[LINE_LENGTH]; + char c; + int first = p_info[i].first_sector; + int last = p_info[i].last_sector; + int offset = 0; + int flags = 0; + int id = LINUX; + int num = -1; + int num_sects = last - first + 1; + int len, ext, j; + + if (p_info[i].num == PRI_OR_LOG) { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Primary or logical [pl]: "); + clrtoeol(); + refresh(); + while (toupper(c = getch()) != 'P' && toupper(c) != 'L' && c != ESC); + if (toupper(c) == 'P') + num = find_primary(); + else if (toupper(c) == 'L') + num = find_logical(i); + else + return; + } else if (p_info[i].num == PRIMARY) + num = find_primary(); + else if (p_info[i].num == LOGICAL) + num = find_logical(i); + else + print_warning("!!! Internal error !!!"); + + sprintf(def, "%.2f", ceiling(num_sects/20.48)/100); + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Size (in MB): "); + if ((len = get_string(response, LINE_LENGTH, def)) <= 0 && + len != GS_DEFAULT) + return; + else if (len > 0) { +#define num_cyls(bytes) (round_int(bytes/SECTOR_SIZE/(sectors*heads))) + for (j = 0; + j < len-1 && (isdigit(response[j]) || response[j] == '.'); + j++); + if (toupper(response[j]) == 'K') { + num_sects = num_cyls(atof(response)*1024)*sectors*heads; + } else if (toupper(response[j]) == 'M') { + num_sects = num_cyls(atof(response)*1024*1024)*sectors*heads; + } else if (toupper(response[j]) == 'C') { + num_sects = round_int(atof(response))*sectors*heads; + } else if (toupper(response[j]) == 'S') { + num_sects = round_int(atof(response)); + } else { + num_sects = num_cyls(atof(response)*1024*1024)*sectors*heads; + } + } + + if (num_sects <= 0 || + num_sects > p_info[i].last_sector - p_info[i].first_sector + 1) + return; + + if (num_sects < p_info[i].last_sector - p_info[i].first_sector + 1) { + /* Determine where inside free space to put partition. + */ + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Add partition at beginning or end of free space [be]: "); + clrtoeol(); + refresh(); + while (toupper(c = getch()) != 'B' && toupper(c) != 'E' && c != ESC); + if (toupper(c) == 'B') + last = first + num_sects - 1; + else if (toupper(c) == 'E') + first = last - num_sects + 1; + else + return; + } + + if (IS_LOGICAL(num) && ext_info.id != EXTENDED) { + /* We want to add a logical partition, but need to create an + * extended partition first. + */ + if ((ext = find_primary()) < 0) { + print_warning(NEED_EXT); + return; + } + (void)add_part(ext, EXTENDED, 0, first, last, + (first == 0 ? sectors : 0)); + } + + if (IS_LOGICAL(num)) + inc_logical(i); + + /* Now we have a complete partition to ourselves */ + if (first == 0 || IS_LOGICAL(num)) + offset = sectors; + + (void)add_part(num, id, flags, first, last, offset); +} + +void clear_p_info(void) +{ + num_parts = 1; + p_info[0].first_sector = 0; + p_info[0].last_sector = sectors*heads*cylinders - 1; + p_info[0].offset = 0; + p_info[0].flags = 0; + p_info[0].id = FREE_SPACE; + p_info[0].num = PRI_OR_LOG; + + ext_info.first_sector = 0; + ext_info.last_sector = 0; + ext_info.offset = 0; + ext_info.flags = 0; + ext_info.id = FREE_SPACE; + ext_info.num = PRIMARY; +} + +void fill_p_info(void) +{ + int p, i; + struct hd_geometry geometry; + 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); + read_sector(buffer.c.b, 0); + + if (!ioctl(fd, HDIO_GETGEO, &geometry)) { + if (!heads) + heads = geometry.heads; + if (!sectors) + sectors = geometry.sectors; + if (!cylinders) + cylinders = geometry.cylinders; + } + + if (!heads || !sectors || !cylinders) + fatal(BAD_GEOMETRY); + + clear_p_info(); + + if (!zero_table) { + for (i = 0; i < 4; i++) { + 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), + 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))) { + fatal(BAD_PRIMARY); + } + if (buffer.p.part[i].sys_ind == EXTENDED) + tmp_ext = ext_info; + } + + if (tmp_ext.id == EXTENDED) { + ext_info = tmp_ext; + logical_sectors[logical] = ext_info.first_sector; + 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); + p++); + if (p > 3) + fatal(BAD_LOGICAL); + + if (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)) { + fatal(BAD_LOGICAL); + } + + for (p = 0; + p < 4 && buffer.p.part[p].sys_ind != 5; + p++); + if (p < 4) { + logical_sectors[logical] = + ext_info.first_sector + buffer.p.part[p].start_sect; + read_sector(buffer.c.b, logical_sectors[logical++]); + } + } while (p < 4 && logical < MAXIMUM_PARTS-4); + } + } +} + +void fill_part_table(struct partition *p, partition_info *pi) +{ + int sects; + + p->boot_ind = pi->flags; + p->sys_ind = pi->id; + if (IS_LOGICAL(pi->num)) + p->start_sect = pi->offset; + else + p->start_sect = pi->first_sector + pi->offset; + p->nr_sects = pi->last_sector - (pi->first_sector+pi->offset) + 1; + sects = (((pi->first_sector+pi->offset)/(sectors*heads) > 1023) ? + heads*sectors*1024 - 1 : pi->first_sector+pi->offset); + set_hsc(p->head, p->sector, p->cyl, sects); + sects = ((pi->last_sector/(sectors*heads) > 1023) ? + heads*sectors*1024 - 1 : pi->last_sector); + set_hsc(p->end_head, p->end_sector, p->end_cyl, sects); +} + +void fill_primary_table(partition_table *buffer) +{ + int i; + + /* Zero out existing table */ + for (i = 0x1BE; i < SECTOR_SIZE; i++) + buffer->c.b[i] = 0; + + for (i = 0; i < num_parts; i++) + 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) + fill_part_table(&(buffer->p.part[ext_info.num]), &ext_info); + + buffer->p.flag = PART_TABLE_FLAG; +} + +void fill_logical_table(partition_table *buffer, partition_info *pi) +{ + struct partition *p; + int i, sects; + + for (i = 0; i < logical && pi->first_sector != logical_sectors[i]; i++); + if (i == logical || buffer->p.flag != (unsigned short)PART_TABLE_FLAG) + for (i = 0; i < SECTOR_SIZE; i++) + buffer->c.b[i] = 0; + + /* Zero out existing table */ + for (i = 0x1BE; i < SECTOR_SIZE; i++) + buffer->c.b[i] = 0; + + fill_part_table(&(buffer->p.part[0]), pi); + + for (i = 0; + i < num_parts && pi->num != p_info[i].num - 1; + i++); + + if (i < num_parts) { + p = &(buffer->p.part[1]); + pi = &(p_info[i]); + + p->boot_ind = 0; + p->sys_ind = 5; + p->start_sect = pi->first_sector - ext_info.first_sector; + p->nr_sects = pi->last_sector - pi->first_sector + 1; + sects = ((pi->first_sector/(sectors*heads) > 1023) ? + heads*sectors*1024 - 1 : pi->first_sector); + set_hsc(p->head, p->sector, p->cyl, sects); + sects = ((pi->last_sector/(sectors*heads) > 1023) ? + heads*sectors*1024 - 1 : pi->last_sector); + set_hsc(p->end_head, p->end_sector, p->end_cyl, sects); + } + + buffer->p.flag = PART_TABLE_FLAG; +} + +void write_part_table(void) +{ + int i, done = FALSE, len; + partition_table buffer; + 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 (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(); + + 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); +} + +void fp_printf(FILE *fp, char *format, ...) +{ + va_list args; + char buf[1024]; + int y, x; + + va_start(args, format); + vsprintf(buf, format, args); + va_end(args); + + if (fp == NULL) { + /* The following works best if the string to be printed has at + most only one newline. */ + printw("%s", buf); + getyx(stdscr, y, x); + if (y >= COMMAND_LINE_Y-2) { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Press any key to continue..."); + clrtoeol(); + refresh(); + (void)getch(); + erase(); + move(0, 0); + } + } else + fprintf(fp, "%s", buf); +} + +#define MAX_PER_LINE 16 +void print_file_buffer(FILE *fp, char *buffer) +{ + int i,l; + + for (i = 0, l = 0; i < SECTOR_SIZE; i++, l++) { + if (l == 0) + fp_printf(fp, "0x%03X:", i); + fp_printf(fp, " %02X", (unsigned char) buffer[i]); + if (l == MAX_PER_LINE - 1) { + fp_printf(fp, "\n"); + l = -1; + } + } + if (l > 0) + fp_printf(fp, "\n"); + fp_printf(fp, "\n"); +} + +void print_raw_table(void) +{ + int i, to_file; + partition_table buffer; + char fname[LINE_LENGTH]; + FILE *fp; + + if (print_only) { + fp = stdout; + to_file = TRUE; + } else { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter filename or press RETURN to display on screen: "); + + if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) + return; + + if (to_file) { + if ((fp = fopen(fname, "w")) == NULL) { + char errstr[LINE_LENGTH]; + sprintf(errstr, PRINT_OPEN_ERR, fname); + print_warning(errstr); + return; + } + } else { + fp = NULL; + erase(); + move(0, 0); + } + } + + fp_printf(fp, "Disk Drive: %s\n", disk_device); + + 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)) { + read_sector(buffer.c.b, p_info[i].first_sector); + fill_logical_table(&buffer, &(p_info[i])); + print_file_buffer(fp, buffer.c.b); + } + + if (to_file) { + if (!print_only) + fclose(fp); + } else { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Press any key to continue..."); + clrtoeol(); + refresh(); + (void)getch(); + } +} + +void print_p_info_entry(FILE *fp, partition_info *p) +{ + int size; + char part_str[21]; + + if (p->id == UNUSABLE) + fp_printf(fp, " None "); + else if (p->id == FREE_SPACE && p->num == PRI_OR_LOG) + fp_printf(fp, " Pri/Log"); + else if (p->id == FREE_SPACE && p->num == PRIMARY) + fp_printf(fp, " Primary"); + else if (p->id == FREE_SPACE && p->num == LOGICAL) + fp_printf(fp, " Logical"); + else + fp_printf(fp, "%2d %-7.7s", p->num+1, + IS_LOGICAL(p->num) ? "Logical" : "Primary"); + + fp_printf(fp, " "); + + fp_printf(fp, "%7d%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, + (((p->last_sector+1)/(sectors*heads)) != + ((float)(p->last_sector+1)/(sectors*heads)) ? + '*' : ' ')); + + fp_printf(fp, " "); + + fp_printf(fp, "%6d%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, + ((size/(sectors*heads)) != ((float)size/(sectors*heads)) ? + '*' : ' ')); + + fp_printf(fp, " "); + + if (p->id == UNUSABLE) + sprintf(part_str, "%.16s", "Unusable"); + else if (p->id == FREE_SPACE) + sprintf(part_str, "%.16s", "Free Space"); + else if (partition_type[p->id]) + sprintf(part_str, "%.16s (%02X)", partition_type[p->id], p->id); + else + sprintf(part_str, "%.16s (%02X)", "Unknown", p->id); + fp_printf(fp, "%-21.21s", part_str); + + fp_printf(fp, " "); + + if (p->flags == ACTIVE_FLAG) + fp_printf(fp, "Boot (%02X)", p->flags); + else if (p->flags != 0) + fp_printf(fp, "Unknown (%02X)", p->flags); + else + fp_printf(fp, "None (%02X)", p->flags); + + fp_printf(fp, "\n"); +} + +void print_p_info(void) +{ + char fname[LINE_LENGTH]; + FILE *fp; + int i, to_file, pext = (ext_info.id == EXTENDED); + + if (print_only) { + fp = stdout; + to_file = TRUE; + } else { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter filename or press RETURN to display on screen: "); + + if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) + return; + + if (to_file) { + if ((fp = fopen(fname, "w")) == NULL) { + char errstr[LINE_LENGTH]; + sprintf(errstr, PRINT_OPEN_ERR, fname); + print_warning(errstr); + return; + } + } else { + fp = NULL; + erase(); + move(0, 0); + } + } + + 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"); + + for (i = 0; i < num_parts; i++) { + if (pext && (p_info[i].first_sector >= ext_info.first_sector)) { + print_p_info_entry(fp,&ext_info); + pext = FALSE; + } + print_p_info_entry(fp, &(p_info[i])); + } + + if (to_file) { + if (!print_only) + fclose(fp); + } else { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Press any key to continue..."); + clrtoeol(); + refresh(); + (void)getch(); + } +} + +void print_part_entry(FILE *fp, int num, partition_info *pi) +{ + int first = 0, start = 0, end = 0, size = 0; + int ss = 0, sh = 0, sc = 0; + int es = 0, eh = 0, ec = 0; + int flags = 0, id = 0; + + if (pi != NULL) { + flags = pi->flags; + id = pi->id; + + if (IS_LOGICAL(num)) + first = pi->offset; + else + first = pi->first_sector + pi->offset; + + start = pi->first_sector + pi->offset; + end = pi->last_sector; + size = end - start + 1; + if ((start/(sectors*heads)) > 1023) + start = heads*sectors*1024 - 1; + if ((end/(sectors*heads)) > 1023) + end = heads*sectors*1024 - 1; + + ss = start % sectors + 1; + start /= sectors; + sh = start % heads; + sc = start / heads; + + es = end % sectors + 1; + end /= sectors; + eh = end % heads; + ec = end / heads; + } + + fp_printf(fp, "%2d 0x%02X %4d %4d %4d 0x%02X %4d %4d %4d %7d %7d\n", + num+1, flags, sh, ss, sc, id, eh, es, ec, first, size); +} + + +void print_part_table(void) +{ + int i, j, to_file; + char fname[LINE_LENGTH]; + FILE *fp; + + if (print_only) { + fp = stdout; + to_file = TRUE; + } else { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter filename or press RETURN to display on screen: "); + + if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) + return; + + if (to_file) { + if ((fp = fopen(fname, "w")) == NULL) { + char errstr[LINE_LENGTH]; + sprintf(errstr, PRINT_OPEN_ERR, fname); + print_warning(errstr); + return; + } + } else { + fp = NULL; + erase(); + move(0, 0); + } + } + + 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"); + + for (i = 0; i < 4; i++) { + for (j = 0; + j < num_parts && (p_info[j].id <= 0 || p_info[j].num != i); + j++); + if (j < num_parts) { + print_part_entry(fp, i, &(p_info[j])); + } else if (ext_info.id == EXTENDED && ext_info.num == i) { + print_part_entry(fp, i, &ext_info); + } else { + print_part_entry(fp, i, NULL); + } + } + + for (i = 0; i < num_parts; i++) + if (IS_LOGICAL(p_info[i].num)) + print_part_entry(fp, p_info[i].num, &(p_info[i])); + + if (to_file) { + if (!print_only) + fclose(fp); + } else { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Press any key to continue..."); + clrtoeol(); + refresh(); + (void)getch(); + } +} + +void print_tables(void) +{ + int done = FALSE; + + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Print format [rst]: "); + clrtoeol(); + refresh(); + + while (!done) + switch (toupper(getch())) { + case 'R': + print_raw_table(); + done = TRUE; + break; + case 'S': + print_p_info(); + done = TRUE; + break; + case 'T': + print_part_table(); + done = TRUE; + break; + case ESC: + done = TRUE; + break; + } +} + +#define END_OF_HELP "EOHS!" +#define NEW_HELP_SCREEN "SNHS!" +void display_help() +{ + char *help_text[] = { + "Help Screen for cfdisk " VERSION, + "", + "This is cfdisk, a curses based disk partitioning programs, which", + "allows you to create, delete and modify partitions on your hard", + "disk drive.", + "", + "Copyright (C) 1994 Kevin E. Martin", + "", + "Command Meaning", + "------- -------", + " b Toggle bootable flag of the current partition", + " d Delete the current partition", + " g Change cylinders, heads, sectors-per-track parameters", + " WARNING: This option should only be used by people who", + " know what they are doing.", + " h Print this screen", + " m Maximize disk usage of the current partition", + " Note: This may make the partition incompatible with", + " DOS, OS/2, ...", + " n Create new partition from free space", + " p Print partition table to the screen or to a file", + " There are several different formats for the partition", + " that you can choose from:", + " r - Raw data (exactly what would be written to disk)", + " s - Table ordered by sectors", + " t - Table in raw format", + " q Quit program without writing partition table", + " t Change the filesystem type", + " u Change units of the partition size display", + " Rotates through Mb, sectors and cylinders", + " W Write partition table to disk (must enter upper case W)", + " Since this might destroy data on the disk, you must", + " either confirm or deny the write by entering `yes' or", + " `no'", + "Up Arrow Move cursor to the previous partition", + "Down Arrow Move cursor to the next partition", + "CTRL-L Redraws the screen", + " ? Print this screen", + "", + "Note: All of the commands can be entered with either upper or lower", + "case letters (except for Writes).", + END_OF_HELP + }; + + int cur_line = 0; + FILE *fp = NULL; + + erase(); + move(0, 0); + while (strcmp(help_text[cur_line], END_OF_HELP)) + if (!strcmp(help_text[cur_line], NEW_HELP_SCREEN)) { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Press any key to continue..."); + clrtoeol(); + refresh(); + (void)getch(); + erase(); + move(0, 0); + cur_line++; + } else + fp_printf(fp, "%s\n", help_text[cur_line++]); + + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Press any key to continue..."); + clrtoeol(); + refresh(); + (void)getch(); +} + +int change_geometry(void) +{ + int ret_val = FALSE; + int done = FALSE; + char def[LINE_LENGTH]; + char response[LINE_LENGTH]; + int tmp_val; + + while (!done) { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Change disk geometry information [chs]: "); + clrtoeol(); + refresh(); + + clear_warning(); + + switch (toupper(getch())) { + case 'C': + sprintf(def, "%d", cylinders); + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter the number of cylinders: "); + if (get_string(response, LINE_LENGTH, def) > 0) { + tmp_val = atoi(response); + if (tmp_val > 0 && tmp_val <= MAX_CYLINDERS) { + cylinders = tmp_val; + ret_val = TRUE; + } else + print_warning(BAD_CYLINDERS); + } + break; + case 'H': + sprintf(def, "%d", heads); + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter the number of heads: "); + if (get_string(response, LINE_LENGTH, def) > 0) { + tmp_val = atoi(response); + if (tmp_val > 0 && tmp_val <= MAX_HEADS) { + heads = tmp_val; + ret_val = TRUE; + } else + print_warning(BAD_HEADS); + } + break; + case 'S': + sprintf(def, "%d", sectors); + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter the number of sectors per track: "); + if (get_string(response, LINE_LENGTH, def) > 0) { + tmp_val = atoi(response); + if (tmp_val > 0 && tmp_val <= MAX_SECTORS) { + sectors = tmp_val; + ret_val = TRUE; + } else + print_warning(BAD_SECTORS); + } + break; + case ESC: + case CR: + done = TRUE; + break; + default: + putchar(BELL); + break; + } + } + + 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) { + if (p_info[num_parts-1].id == FREE_SPACE || + p_info[num_parts-1].id == UNUSABLE) + remove_part(num_parts-1); + else + del_part(num_parts-1); + } + + p_info[num_parts-1].last_sector = heads*sectors*cylinders - 1; + + 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 (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; + } else { + insert_part(num_parts, PRI_OR_LOG, FREE_SPACE, 0, + p_info[num_parts-1].last_sector+1, + heads*sectors*cylinders-1, 0); + } + } + + /* Make sure the partitions are correct */ + check_part_info(); + } + + return ret_val; +} + +void change_id(int i) +{ + char id[LINE_LENGTH], def[LINE_LENGTH]; + int num_types = 0; + int num_across, num_down; + int len, new_id = LINUX; + int y_start, y_end; + int j, pos; + + for (num_types = 0, j = 1; j < NUM_PART_TYPES; j++) + if (partition_type[j]) + num_types++; + + num_across = COLS/COL_ID_WIDTH; + num_down = (((float)num_types)/num_across + 1); + y_start = COMMAND_LINE_Y - 1 - num_down; + if (y_start > DISK_TABLE_START+cur_part+4) + y_start = DISK_TABLE_START+cur_part+4; + y_end = y_start + num_down - 1; + + for (j = y_start - 1; j <= y_end + 1; j++) { + move(j, 0); + clrtoeol(); + } + + for (pos = 0, j = 1; j < NUM_PART_TYPES; j++) + if (partition_type[j]) { + move(y_start + pos % num_down, (pos/num_down)*COL_ID_WIDTH + 1); + printw("%02X %-16.16s", j, partition_type[j]); + pos++; + } + + sprintf(def, "%02X", new_id); + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Enter filesystem type: "); + if ((len = get_string(id, 2, def)) <= 0 && len != GS_DEFAULT) + return; + + if (len != GS_DEFAULT) { + if (!isxdigit(id[0])) + return; + new_id = (isdigit(id[0]) ? id[0] - '0' : tolower(id[0]) - 'a' + 10); + if (len == 2) + if (isxdigit(id[1])) + new_id = new_id*16 + + (isdigit(id[1]) ? id[1] - '0' : tolower(id[1]) - 'a' + 10); + else + return; + } + + if (new_id == 0) + print_warning(ID_EMPTY); + else if (new_id == EXTENDED) + print_warning(ID_EXT); + else + p_info[i].id = new_id; +} + +void draw_partition(int i) +{ + int size, j; + int y = i + DISK_TABLE_START + 2 - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN; + + if (!arrow_cursor) { + move(y, 0); + for (j = 0; j < COLS; j++) + addch(' '); + } + + if (p_info[i].id > 0) { + mvprintw(y, NAME_START, + "%s%d", disk_device, p_info[i].num+1); + if (p_info[i].flags) { + if (p_info[i].flags == ACTIVE_FLAG) + mvaddstr(y, FLAGS_START, "Boot"); + else + mvprintw(y, FLAGS_START, "Unk(%02X)", p_info[i].flags); + if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) { + if (p_info[i].offset != sectors) + addstr(", NC"); + } else { + if (p_info[i].offset != 0) + addstr(", NC"); + } + } else { + if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) { + if (p_info[i].offset != sectors) + mvaddstr(y, FLAGS_START, "NC"); + } else { + if (p_info[i].offset != 0) + mvaddstr(y, FLAGS_START, "NC"); + } + } + } + mvaddstr(y, PTYPE_START, + (p_info[i].id == UNUSABLE ? "" : + (IS_LOGICAL(p_info[i].num) ? "Logical" : + (p_info[i].num >= 0 ? "Primary" : + (p_info[i].num == PRI_OR_LOG ? "Pri/Log" : + (p_info[i].num == PRIMARY ? "Primary" : "Logical")))))); + if (p_info[i].id == UNUSABLE) + mvaddstr(y, FSTYPE_START, "Unusable"); + else if (p_info[i].id == FREE_SPACE) + mvaddstr(y, FSTYPE_START, "Free Space"); + else if (partition_type[p_info[i].id]) + mvaddstr(y, FSTYPE_START, partition_type[p_info[i].id]); + else + mvprintw(y, FSTYPE_START, "Unknown (%02X)", p_info[i].id); + + size = p_info[i].last_sector - p_info[i].first_sector + 1; + if (display_units == SECTORS) + mvprintw(y, SIZE_START, "%9d", size); + else if (display_units == CYLINDERS) + mvprintw(y, SIZE_START, "%9d", size/(sectors*heads)); + else + mvprintw(y, SIZE_START, "%9.2f", ceiling(size/20.48)/100); + if (((size/(sectors*heads)) != ceiling(size/(sectors*(float)heads))) || + ((p_info[i].first_sector/(sectors*heads)) != + ceiling(p_info[i].first_sector/(sectors*heads)))) + mvprintw(y, COLUMNS-1, "*"); +} + +void init_const(void) +{ + if (!defined) { + NAME_START = (((float)NAME_START)/COLUMNS)*COLS; + FLAGS_START = (((float)FLAGS_START)/COLUMNS)*COLS; + PTYPE_START = (((float)PTYPE_START)/COLUMNS)*COLS; + FSTYPE_START = (((float)FSTYPE_START)/COLUMNS)*COLS; + SIZE_START = (((float)SIZE_START)/COLUMNS)*COLS; + COMMAND_LINE_X = (((float)COMMAND_LINE_X)/COLUMNS)*COLS; + + COMMAND_LINE_Y = LINES - 4; + WARNING_START = LINES - 2; + + if ((NUM_ON_SCREEN = COMMAND_LINE_Y - DISK_TABLE_START - 3) <= 0) + NUM_ON_SCREEN = 1; + + COLUMNS = COLS; + defined = TRUE; + } +} + +void draw_screen(void) +{ + int i; + char *line; + + line = (char *)malloc((COLS+1)*sizeof(char)); + + if (warning_last_time) { + for (i = 0; i < COLS; i++) { + move(WARNING_START, i); + line[i] = inch(); + } + line[COLS] = 0; + } + + erase(); + + if (warning_last_time) + mvaddstr(WARNING_START, 0, line); + + + sprintf(line, "cfdisk %s", VERSION); + mvaddstr(HEADER_START, (COLS-strlen(line))/2, line); + sprintf(line, "Disk Drive: %s", disk_device); + mvaddstr(HEADER_START+2, (COLS-strlen(line))/2, line); + sprintf(line, "Heads: %d Sectors per Track: %d Cylinders: %d", + heads, sectors, cylinders); + mvaddstr(HEADER_START+3, (COLS-strlen(line))/2, line); + + mvaddstr(DISK_TABLE_START, NAME_START, "Name"); + mvaddstr(DISK_TABLE_START, FLAGS_START, "Flags"); + mvaddstr(DISK_TABLE_START, PTYPE_START, "Part Type"); + mvaddstr(DISK_TABLE_START, FSTYPE_START, "FS Type"); + if (display_units == SECTORS) + mvaddstr(DISK_TABLE_START, SIZE_START, " Sectors"); + else if (display_units == CYLINDERS) + mvaddstr(DISK_TABLE_START, SIZE_START, "Cylinders"); + else + mvaddstr(DISK_TABLE_START, SIZE_START, "Size (MB)"); + + move(DISK_TABLE_START+1, 1); + for (i = 1; i < COLS-1; i++) + addch('-'); + + if (NUM_ON_SCREEN >= num_parts) + for (i = 0; i < num_parts; i++) + draw_partition(i); + else + for (i = (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN; + i < NUM_ON_SCREEN + (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN && + i < num_parts; + i++) + draw_partition(i); + + free(line); +} + +int draw_cursor(int move) +{ + if (move != 0 && (cur_part + move < 0 || cur_part + move >= num_parts)) + return -1; + + if (arrow_cursor) + mvaddstr(DISK_TABLE_START + cur_part + 2 + - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, " "); + else + draw_partition(cur_part); + + cur_part += move; + + if (((cur_part - move)/NUM_ON_SCREEN)*NUM_ON_SCREEN != + (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN) + draw_screen(); + + if (arrow_cursor) + mvaddstr(DISK_TABLE_START + cur_part + 2 + - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, "-->"); + else { + standout(); + draw_partition(cur_part); + standend(); + } + + 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; + char command; + + initscr(); + old_SIGINT = signal(SIGINT, die); + old_SIGTERM = signal(SIGTERM, die); +#ifdef DEBUG + signal(SIGINT, old_SIGINT); + signal(SIGTERM, old_SIGTERM); +#endif + + cbreak(); + noecho(); + nonl(); + + init_const(); + + fill_p_info(); + + draw_screen(); + + while (!done) { + (void)draw_cursor(0); + + if (p_info[cur_part].id == FREE_SPACE) + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Command [hnpquW?]: "); + else if (p_info[cur_part].id > 0) + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Command [bdhmpqtuW?]: "); + else + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Command [hpquW?]: "); + + clrtoeol(); + refresh(); + + clear_warning(); + + switch (command = getch()) { + case 'B': + case 'b': + if (p_info[cur_part].id > 0) + p_info[cur_part].flags ^= 0x80; + else + print_warning(NO_FLAGS); + break; + case 'D': + case 'd': + if (p_info[cur_part].id > 0) { + del_part(cur_part); + if (cur_part >= num_parts) + cur_part = num_parts - 1; + draw_screen(); + } else + print_warning(DEL_EMPTY); + break; + case 'G': + case 'g': + if (change_geometry()) + draw_screen(); + break; + case 'M': + case 'm': + if (p_info[cur_part].id > 0) { + if (p_info[cur_part].first_sector == 0 || + IS_LOGICAL(p_info[cur_part].num)) { + if (p_info[cur_part].offset == sectors) + p_info[cur_part].offset = 1; + else + p_info[cur_part].offset = sectors; + draw_screen(); + } else if (p_info[cur_part].offset != 0) + p_info[cur_part].offset = 0; + else + print_warning(MAX_UNMAXABLE); + } else + print_warning(MAX_UNMAXABLE); + break; + case 'N': + case 'n': + if (p_info[cur_part].id == FREE_SPACE) { + new_part(cur_part); + draw_screen(); + } else if (p_info[cur_part].id == UNUSABLE) + print_warning(ADD_UNUSABLE); + else + print_warning(ADD_EXISTS); + break; + case 'P': + case 'p': + print_tables(); + draw_screen(); + break; + case 'Q': + case 'q': + done = TRUE; + break; + case 'T': + case 't': + if (p_info[cur_part].id > 0) { + change_id(cur_part); + draw_screen(); + } else + print_warning(TYPE_EMPTY); + break; + case 'U': + case 'u': + if (display_units == MEGABYTES) + display_units = SECTORS; + else if (display_units == SECTORS) + display_units = CYLINDERS; + else if (display_units == CYLINDERS) + display_units = MEGABYTES; + draw_screen(); + break; + case 'W': + write_part_table(); + break; + case 'H': + case 'h': + case '?': + display_help(); + draw_screen(); + break; + case ESC: + if ((command = getch()) == '[') { + command = getch(); + switch (command) { + case 'A' : /* Up arrow */ + if (!draw_cursor(-1)) + command = 0; + else + print_warning(NO_MORE_PARTS); + break; + case 'B' : /* Down arrow */ + if (!draw_cursor(1)) + command = 0; + else + print_warning(NO_MORE_PARTS); + break; + case 'C' : /* Right arrow */ + case 'D' : /* Left arrow */ + } + } + if (command) + putchar(BELL); /* CTRL-G */ + break; + case REDRAWKEY: + clear(); + draw_screen(); + break; + default: + print_warning(BAD_COMMAND); + putchar(BELL); /* CTRL-G */ + } + } + + signal(SIGINT, old_SIGINT); + signal(SIGTERM, old_SIGTERM); + mvcur(0, COLS-1, LINES-1, 0); + nl(); + endwin(); + fdexit(0); +} + +void copyright(void) +{ + fprintf(stderr, "Copyright (C) 1994 Kevin E. Martin\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"); + copyright(); +} + +void main(int argc, char **argv) +{ + char c; + int i, len; + + while ((c = getopt(argc, argv, "ac:h:s:vzP:")) != EOF) + switch (c) { + case 'a': + arrow_cursor = TRUE; + break; + case 'c': + cylinders = atoi(optarg); + if (cylinders <= 0 || cylinders > MAX_CYLINDERS) { + fprintf(stderr, "%s: %s\n", argv[0], BAD_CYLINDERS); + exit(1); + } + break; + case 'h': + heads = atoi(optarg); + if (heads <= 0 || heads > MAX_HEADS) { + fprintf(stderr, "%s: %s\n", argv[0], BAD_HEADS); + exit(1); + } + break; + case 's': + sectors = atoi(optarg); + if (sectors <= 0 || sectors > MAX_SECTORS) { + fprintf(stderr, "%s: %s\n", argv[0], BAD_SECTORS); + exit(1); + } + break; + case 'v': + fprintf(stderr, "cfdisk %s\n", VERSION); + copyright(); + exit(0); + case 'z': + zero_table = TRUE; + break; + case 'P': + len = strlen(optarg); + for (i = 0; i < len; i++) { + switch (optarg[i]) { + case 'r': + print_only |= PRINT_RAW_TABLE; + break; + case 's': + print_only |= PRINT_SECTOR_TABLE; + break; + case 't': + print_only |= PRINT_PARTITION_TABLE; + break; + default: + usage(argv[0]); + break; + } + } + break; + default: + usage(argv[0]); + exit(1); + } + + if (argc-optind == 1) + disk_device = argv[optind]; + else if (argc-optind != 0) { + usage(argv[0]); + exit(1); + } else if ((fd = open(DEFAULT_DEVICE, O_RDWR)) < 0) + disk_device = ALTERNATE_DEVICE; + else close(fd); + + if (print_only) { + fill_p_info(); + if (print_only & PRINT_RAW_TABLE) + print_raw_table(); + if (print_only & PRINT_SECTOR_TABLE) + print_p_info(); + if (print_only & PRINT_PARTITION_TABLE) + print_part_table(); + } else + do_curses_fdisk(); +} diff --git a/disk-utils/fdformat.c b/disk-utils/fdformat.c index 7fb78af6a..8b08535a6 100644 --- a/disk-utils/fdformat.c +++ b/disk-utils/fdformat.c @@ -93,7 +93,7 @@ int main(int argc,char **argv) argv++; } if (argc != 2) usage(name); - if (lstat(argv[1],&st) < 0) PERROR(argv[1]); + if (stat(argv[1],&st) < 0) PERROR(argv[1]); if (!S_ISBLK(st.st_mode) || MAJOR(st.st_rdev) != FLOPPY_MAJOR) { fprintf(stderr,"%s: not a floppy device\n",argv[1]); exit(1); diff --git a/disk-utils/fdisk.8 b/disk-utils/fdisk.8 index d1891bb24..395e9c71d 100644 --- a/disk-utils/fdisk.8 +++ b/disk-utils/fdisk.8 @@ -1,6 +1,6 @@ .\" Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu) .\" May be distributed under the GNU General Public License -.TH FDISK 8 "Tue Mar 22 01:00:00 1994" "Linux 1.0" "Linux Programmer's Manual" +.TH FDISK 8 "3 June 1995" "Linux 1.0" "Linux Programmer's Manual" .SH NAME fdisk \- Partition table manipulator for Linux .SH SYNOPSIS diff --git a/disk-utils/fdisk.c b/disk-utils/fdisk.c index 3c0a328d5..f3455fa5f 100644 --- a/disk-utils/fdisk.c +++ b/disk-utils/fdisk.c @@ -31,6 +31,25 @@ * Modified, Wed Jun 22 21:05:30 1994, faith@cs.unc.edu: * Added/changed a few partition type names to conform to cfdisk. * (suggested by Sujal, smpatel@wam.umd.edu) + * Modified 3/5/95 leisner@sdsp.mc.xerox.com -- on -l only open + * devices RDONLY (instead of RDWR). This allows you to + * have the disks as rw-r----- with group disk (and if you + * want is safe to setguid fdisk to disk). + * Modified Sat Mar 11 10:02 1995 with more partition types, faith@cs.unc.edu + * Modified, Thu May 4 01:11:45 1995, esr@snark.thyrsus.com: + * It's user-interface cleanup time. + * Actual error messages for out-of-bounds values (what a concept!). + * Enable read-only access to partition table for learners. + * Smart defaults for most numeric prompts. + * Fixed a bug preventing a partition from crossing cylinder 8064, aeb, 950801. + * Read partition table twice to avoid kernel bug + * (from Daniel Quinlan <quinlan@yggdrasil.com>), Tue Sep 26 10:25:28 1995 + * Modified, Sat Jul 1 23:43:16 MET DST 1995, fasten@cs.bonn.edu: + * editor for NetBSD/i386 (and Linux/Alpha?) disklabels. + * Tue Sep 26 17:07:54 1995: More patches from aeb. Fix segfaults, all >4GB. + * Don't destroy random data if extd partition starts past 4GB, aeb, 950818. + * Don't segfault on bad partition created by previous fdisk. + * */ @@ -49,15 +68,7 @@ #include <linux/hdreg.h> #include <linux/fs.h> -#if defined(__GNUC__) || defined(HAS_LONG_LONG) -typedef long long ext2_loff_t; -#else -typedef long ext2_loff_t; -#endif - -extern ext2_loff_t ext2_llseek(unsigned int fd, - ext2_loff_t offset, - unsigned int origin); +#include "fdisk.h" #define hex_val(c) ({ \ char _c = (c); \ @@ -66,13 +77,12 @@ extern ext2_loff_t ext2_llseek(unsigned int fd, }) -#define VERSION "2.0a (>2GB)" +#define VERSION "2.1 (>4GB)" #define DEFAULT_DEVICE "/dev/hda" #define ALTERNATE_DEVICE "/dev/sda" #define LINE_LENGTH 80 #define MAXIMUM_PARTS 60 -#define SECTOR_SIZE 512 #define PART_TABLE_FLAG 0xaa55 #define table_check(b) ((unsigned short *)((b) + 0x1fe)) #define offset(b, n) ((struct partition *)((b) + 0x1be + \ @@ -91,7 +101,6 @@ extern ext2_loff_t ext2_llseek(unsigned int fd, s |= (sector >> 2) & 0xc0; \ } -#define cround(n) (((n) + display_factor * unit_flag) / display_factor) #define ACTIVE_FLAG 0x80 #define EXTENDED 5 @@ -99,8 +108,8 @@ extern ext2_loff_t ext2_llseek(unsigned int fd, #define LINUX_SWAP 0x82 #define LINUX_NATIVE 0x83 -enum failure {usage, unable_to_open, unable_to_read, unable_to_seek, - unable_to_write, out_of_memory}; +/* normally O_RDWR, -l option gives O_RDONLY */ +static int type_open = O_RDWR; char *disk_device = DEFAULT_DEVICE, /* hda, unless specified */ *line_ptr, /* interactive input */ @@ -113,7 +122,6 @@ char *disk_device = DEFAULT_DEVICE, /* hda, unless specified */ int fd, /* the disk */ ext_index, /* the prime extended partition */ listing = 0, /* no aborts for fdisk -l */ - size_flag = 0, dos_compatible_flag = ~0, partitions = 4; /* maximum partition + 1 */ @@ -133,11 +141,8 @@ struct partition *part_table[MAXIMUM_PARTS] /* partitions */ *ext_pointers[MAXIMUM_PARTS] /* link pointers */ = {NULL, NULL, NULL, NULL}; -struct systypes { - unsigned char index; - char *name; - } sys_types[] = { - {0, "Empty"}, +struct systypes sys_types[] = { /* struct systypes in fdisk.h *//* bf */ + {0, "Empty"}, {1, "DOS 12-bit FAT"}, {2, "XENIX root"}, {3, "XENIX usr"}, @@ -152,7 +157,8 @@ struct systypes { {0x51, "Novell?"}, {0x52, "Microport"}, /* or CPM? */ {0x63, "GNU HURD"}, /* or System V/386? */ - {0x64, "Novell"}, + {0x64, "Novell Netware 286"}, + {0x65, "Novell Netware 386"}, {0x75, "PC/IX"}, {0x80, "Old MINIX"}, /* Minix 1.4a and earlier */ @@ -173,6 +179,8 @@ struct systypes { {0xff, "BBT"} /* (bad track table) */ }; +int nsys_types = sizeof (sys_types) / sizeof (struct systypes); /* bf */ + jmp_buf listingbuf; void fatal(enum failure why) @@ -216,6 +224,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" " d delete a partition\n" " l list known partition types\n" @@ -244,6 +253,7 @@ void xmenu(void) " q quit without saving changes\n" " r return to main menu\n" " s change number of sectors\n" + " v verify the partition table\n" " w write table to disk and exit" ); } @@ -265,10 +275,12 @@ char *partition_type(unsigned char type) return NULL; } -void list_types(void) +/* added parameters to list_types() so fdisklabel + can pass another list of types. +*//* bf */ +void list_types(struct systypes *sys, int size) { - uint last[4], done = 0, next = 0, - size = sizeof(sys_types) / sizeof(struct systypes); + uint last[4], done = 0, next = 0; int i; for (i = 3; i >= 0; i--) @@ -277,8 +289,8 @@ void list_types(void) do { printf("%c%2x %-15.15s", i ? ' ' : '\n', - sys_types[next].index, sys_types[next].name); - next = last[i++] + done; + sys[next].index, sys[next].name); + next = last[i++] + done; if (i > 3 || next >= last[i]) { i = 0; next = ++done; @@ -399,7 +411,7 @@ void read_extended(struct partition *p) offsets[partitions] = extended_offset + p->start_sect; if (!extended_offset) extended_offset = p->start_sect; - if (ext2_llseek(fd, offsets[partitions] + if (ext2_llseek(fd, (ext2_loff_t)offsets[partitions] * SECTOR_SIZE, SEEK_SET) < 0) fatal(unable_to_seek); if (!(buffers[partitions] = (char *) malloc(SECTOR_SIZE))) @@ -443,11 +455,20 @@ void get_boot(void) struct hd_geometry geometry; partitions = 4; - if ((fd = open(disk_device, O_RDWR)) < 0) + if ((fd = open(disk_device, type_open)) < 0) + { + if ((fd = open(disk_device, O_RDONLY)) < 0) fatal(unable_to_open); + else + printf("You will not be able to write the partition table.\n"); + } if (SECTOR_SIZE != read(fd, buffer, SECTOR_SIZE)) fatal(unable_to_read); +#ifdef HDIO_REQ if (!ioctl(fd, HDIO_REQ, &geometry)) { +#else + if (!ioctl(fd, HDIO_GETGEO, &geometry)) { +#endif heads = geometry.heads; sectors = geometry.sectors; cylinders = geometry.cylinders; @@ -492,19 +513,61 @@ char read_char(char *mesg) return *line_ptr; } -uint read_int(uint low, uint high, char *mesg) +/* new function *//* bf */ +int read_hex(struct systypes *sys, int size) { - uint i; + int hex; + + while (1) + { + read_char("Hex code (type L to list codes): "); + if (tolower(*line_ptr) == 'l') + list_types(sys, size); + else if (isxdigit (*line_ptr)) + { + hex = 0; + do + hex = hex << 4 | hex_val(*line_ptr++); + while (isxdigit(*line_ptr)); + return hex; + } + } +} + + +uint read_int(uint low, uint dflt, uint high, enum offset base, char *mesg) +{ + uint i, use_default = 1; char ms[70]; - sprintf(ms, "%s (%d-%d): ", mesg, low, high); + + switch(base) { + case lower: + sprintf(ms, "%s ([%d]-%d): ", mesg, low, high); + break; + case upper: + sprintf(ms, "%s (%d-[%d]): ", mesg, low, high); + break; + case deflt: + sprintf(ms, "%s (%d-[%d]-%d): ", mesg, low, dflt, high); + break; + default: + sprintf(ms, "%s (%d-%d): ", mesg, low, high); + break; + } while (1) { - while (!isdigit(read_char(ms)) && - (!size_flag || *line_ptr != '+')); - if (*line_ptr == '+') { - i = atoi(++line_ptr); - while (isdigit(*line_ptr)) - line_ptr++; + while (!isdigit(read_char(ms)) + && (*line_ptr != '-' && *line_ptr != '+')) + continue; + if (*line_ptr == '+' || *line_ptr == '-') { + if (*line_ptr == '+') + ++line_ptr; + i = atoi(line_ptr); + while (isdigit(*line_ptr)) + { + line_ptr++; + use_default = 0; + } switch (*line_ptr) { case 'c': case 'C': if (!unit_flag) @@ -520,19 +583,38 @@ uint read_int(uint low, uint high, char *mesg) break; default: break; } - i += low; + switch(base) { + case lower: i += low; break; + case upper: i += high; break; + case deflt: i += dflt; break; + } } - else i = atoi(line_ptr); + else + { + i = atoi(line_ptr); + while (isdigit(*line_ptr)) + { + line_ptr++; + use_default = 0; + } + } + if (use_default) + printf("Using default value %d\n", i = dflt); if (i >= low && i <= high) break; + else + printf("Value out of range.\n"); } - size_flag = 0; return i; } int get_partition(int warn, int max) { - int i = read_int(1, max, "Partition number") - 1; + /* + * try to pick a default least likely to do damage, + * in case luser just types a newline + */ + int i = read_int(1, max, max, ignore, "Partition number") - 1; if (warn && !part_table[i]->sys_ind) fprintf(stderr, "Warning: partition %d has empty type\n", @@ -547,7 +629,7 @@ char *const str_units(void) void change_units(void) { - if (unit_flag = !unit_flag) + if ((unit_flag = !unit_flag)) display_factor = 1; else display_factor = heads * sectors; update_units(); @@ -622,7 +704,8 @@ void delete_partition(int i) changed[i - 1] = 1; } else { - part_table[5]->start_sect += + if(part_table[5]) /* prevent SEGFAULT */ + part_table[5]->start_sect += offsets[5] - extended_offset; offsets[5] = extended_offset; changed[5] = 1; @@ -655,6 +738,7 @@ void change_sysid(void) else if (!sys) printf("Partition %d does not exist yet!\n", i + 1); else while (1) { +#if 0 read_char("Hex code (type L to list codes): "); if (tolower(*line_ptr) == 'l') list_types(); @@ -663,6 +747,12 @@ void change_sysid(void) do sys = sys << 4 | hex_val(*line_ptr++); while (isxdigit(*line_ptr)); +#endif + /* The above code has been moved to read_hex () + to avoid having the same code in fdisklabel. + *//* bf */ + sys = read_hex (sys_types, nsys_types); /* bf */ + if (!sys) { delete_partition(i); break; @@ -683,7 +773,9 @@ void change_sysid(void) changed[i] = 1; break; } +#if 0 /* see above *//* bf */ } +#endif } } @@ -744,6 +836,7 @@ static void check_consistency(struct partition *p, int partition) printf("logical=(%d, %d, %d)\n",lec, leh, les); } +#if 0 /* Beginning on cylinder boundary? */ if (pbh != !pbc || pbs != 1) { printf("Partition %i does not start on cylinder " @@ -751,6 +844,7 @@ static void check_consistency(struct partition *p, int partition) printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs); printf("should be (%d, %d, 1)\n", pbc, !pbc); } +#endif /* Ending on cylinder boundary? */ if (peh != (heads - 1) || pes != sectors) { @@ -773,22 +867,22 @@ void list_table(void) cylinders, str_units(), display_factor); if (w < 5) w = 5; - printf("%*s Boot Begin Start End Blocks Id System\n", + printf("%*s Boot Begin Start End Blocks Id System\n", w + 1, "Device"); for (i = 0 ; i < partitions; i++) if ((p = part_table[i])->sys_ind) { - printf("%*s%-2d %c%8d%8d%8d%8d%c %2x %s\n", w, - disk_device, i + 1, - !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG + printf("%*s%-2d %c%9d%9d%9d%9d%c %2x %s\n", w, +/* device */ disk_device, i + 1, +/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG ? '*' : '?', - cround(rounded( calculate(p->head, p->sector, p->cyl), +/* begin */ cround(rounded( calculate(p->head, p->sector, p->cyl), p->start_sect + offsets[i])), - cround(p->start_sect + offsets[i]), - cround(p->start_sect + offsets[i] + p->nr_sects +/* start */ cround(p->start_sect + offsets[i]), +/* end */ cround(p->start_sect + offsets[i] + p->nr_sects - (p->nr_sects ? 1: 0)), - p->nr_sects / 2, p->nr_sects & 1 ? '+' : ' ', - p->sys_ind, - (type = partition_type(p->sys_ind)) ? +/* odd flag on end */ p->nr_sects / 2, p->nr_sects & 1 ? '+' : ' ', +/* type id */ p->sys_ind, +/* type name */ (type = partition_type(p->sys_ind)) ? type : "Unknown"); check_consistency(p, i); } @@ -824,7 +918,9 @@ void x_list_table(int extend) void check_bounds(uint *first, uint *last) { int i; - uint max = 256 * 63 * 1024; + uint max = 0xffffffff; /* used to be 256 * 63 * 1024 + but that made it impossible to add a + partition crossing cylinder 8064 */ struct partition *p = part_table[0]; for (i = 0; i < partitions; p = part_table[++i]) @@ -863,7 +959,7 @@ void check(int n, uint h, uint s, uint c, uint start) if (real_c >= cylinders) fprintf(stderr, "Partitions %d: cylinder %d greater than " "maximum %d\n", n, real_c + 1, cylinders); - if (start != total) + if (cylinders <= 1024 && start != total) fprintf(stderr, "Partition %d: previous sectors %d disagrees with " "total %d\n", n, start, total); @@ -980,9 +1076,9 @@ void add_partition(int n, int sys) } if (!read && start == temp) { uint i; - temp = 0; - start = read_int(cround(i = (stop = start) + (n > 4)), - cround(limit), mesg); + i = (stop = start) + (n > 4); + start = read_int(cround(i), cround(i), cround(limit), + ignore, mesg); if (unit_flag) { start = (start - 1) * display_factor; if (start < i) start = i; @@ -1012,8 +1108,8 @@ void add_partition(int n, int sys) else { sprintf(mesg, "Last %s or +size or +sizeM or +sizeK", str_units()); - size_flag = 1; - stop = read_int(cround(start), cround(limit), mesg); + stop = read_int(cround(start), cround(limit), cround(limit), + lower, mesg); if (unit_flag) { stop = stop * display_factor - 1; if (stop >limit) @@ -1099,6 +1195,10 @@ void new_partition(void) EXTENDED); return; } + else + printf("Invalid partition number " + "for type `%c'\n", c); + } } @@ -1110,7 +1210,7 @@ void write_table(void) for (i = 3; i < partitions; i++) if (changed[i]) { *table_check(buffers[i]) = PART_TABLE_FLAG; - if (ext2_llseek(fd, offsets[i] + if (ext2_llseek(fd, (ext2_loff_t)offsets[i] * SECTOR_SIZE, SEEK_SET) < 0) fatal(unable_to_seek); if (write(fd, buffers[i], SECTOR_SIZE) != SECTOR_SIZE) @@ -1123,15 +1223,25 @@ void write_table(void) "(Reboot to ensure the partition table has been updated.)\n"); sync(); sleep(2); - if (i = ioctl(fd, BLKRRPART)) - error = errno; + if (i = ioctl(fd, BLKRRPART)) { + error = errno; + } else { + /* some kernel versions (1.2.x) seem to have trouble + rereading the partition table, but if asked to do it + twice, the second time works. - biro@yggdrasil.com */ + sync(); + sleep(2); + if(i = ioctl(fd, BLKRRPART)) + error = errno; + } + close(fd); printf("Syncing disks.\n"); sync(); sleep(4); /* for sync() */ - if (i) + if (i < 0) printf("Re-read table failed with error %d: %s.\nReboot your " "system to ensure the partition table is updated.\n", error, strerror(error)); @@ -1185,8 +1295,9 @@ void move_begin(int i) } first = rounded(calculate(p->head, p->sector, p->cyl), p->start_sect + offsets[i]); - new = read_int(first, p->start_sect + p->nr_sects + offsets[i] - 1, - "New beginning of data") - offsets[i]; + new = read_int(first, first, + p->start_sect + p->nr_sects + offsets[i] - 1, + lower, "New beginning of data") - offsets[i]; if (new != p->nr_sects) { first = p->nr_sects + p->start_sect - new; @@ -1203,15 +1314,16 @@ void xselect(void) switch (tolower(read_char("Expert command (m for help): "))) { case 'b': move_begin(get_partition(0, partitions)); break; - case 'c': cylinders = read_int(1, 65535, - "Number of cylinders"); - warn_cylinders(); + case 'c': cylinders = read_int(1, cylinders, 65535, + deflt, "Number of cylinders"); + warn_cylinders(); break; case 'd': print_raw(); break; case 'e': x_list_table(1); break; - case 'h': heads = read_int(1, 256, "Number of heads"); + case 'h': heads = read_int(1, heads, 256, deflt, + "Number of heads"); update_units(); break; case 'p': x_list_table(0); @@ -1219,7 +1331,7 @@ void xselect(void) case 'q': close(fd); exit(0); case 'r': return; - case 's': sectors = read_int(1, 63, + case 's': sectors = read_int(1, sectors, 63, deflt, "Number of sectors"); if (dos_compatible_flag) { sector_offset = sectors; @@ -1229,6 +1341,8 @@ void xselect(void) } update_units(); break; + case 'v': verify(); + break; case 'w': write_table(); default: xmenu(); } @@ -1239,13 +1353,21 @@ void try(char *device) { disk_device = device; if (!setjmp(listingbuf)) - if ((fd = open(disk_device, O_RDWR)) >= 0) { + if ((fd = open(disk_device, type_open)) >= 0) { close(fd); get_boot(); list_table(); if (partitions > 4) delete_partition(ext_index); - } + } else { + /* Ignore other errors, since we try IDE + and SCSI hard disks which may not be + installed on the system. */ + if(errno == EACCES) { + fprintf(stderr, "Cannot open %s\n", device); + exit(1); + } + } } void main(int argc, char **argv) @@ -1259,6 +1381,7 @@ void main(int argc, char **argv) exit(0); case 'l': listing = 1; + type_open = O_RDONLY; try("/dev/hda"); try("/dev/hdb"); try("/dev/hdc"); @@ -1301,22 +1424,29 @@ void main(int argc, char **argv) disk_device = ALTERNATE_DEVICE; else close(fd); - get_boot(); if (argc == 1) printf("Using %s as default device!\n", disk_device); + get_boot(); while (1) { putchar('\n'); switch (tolower(read_char("Command (m for help): "))) { case 'a': toggle_active(get_partition(1, partitions)); break; +/* There should be a define which allows to turn off disklabel support so as + not to make fdisk larger than necessary on installation boot disks. +*/ +#if 1 /* #ifndef NO_DISKLABEL_SUPPORT */ + case 'b': bselect(); /* bf */ + break; +#endif case 'c': toggle_dos(); break; case 'd': delete_partition( get_partition(1, partitions)); break; - case 'l': list_types(); + case 'l': list_types(sys_types, nsys_types); /* bf */ break; case 'n': new_partition(); break; diff --git a/disk-utils/fdisk.h b/disk-utils/fdisk.h new file mode 100644 index 000000000..4f23fd8a3 --- /dev/null +++ b/disk-utils/fdisk.h @@ -0,0 +1,47 @@ +/* + fdisk.h +*/ + +#define SECTOR_SIZE 512 +#define NETBSD_PARTITION 0xa5 +#define cround(n) (((n) + display_factor * unit_flag) / display_factor) + +#if defined(__GNUC__) || defined(HAS_LONG_LONG) +typedef long long ext2_loff_t; +#else +typedef long ext2_loff_t; +#endif + +extern ext2_loff_t ext2_llseek(unsigned int fd, + ext2_loff_t offset, + unsigned int origin); + +enum failure {usage, unable_to_open, unable_to_read, unable_to_seek, + unable_to_write, out_of_memory}; + +enum offset {ignore, lower, deflt, upper}; + +struct systypes { + unsigned char index; + char *name; +}; + +/* prototypes for fdisk.c */ +extern char *disk_device, + *line_ptr; +extern int fd, + partitions; +extern uint unit_flag, + display_factor; +extern struct partition *part_table[]; +extern void fatal(enum failure why); +extern int get_partition(int warn, int max); +extern void list_types(struct systypes *sys, int size); +extern int read_line (void); +extern char read_char(char *mesg); +extern int read_hex(struct systypes *sys, int size); +uint read_int(uint low, uint dflt, uint high, enum offset base, char *mesg); +extern char *const str_units(void); + +/* prototypes for fdisklabel.c */ +extern void bselect(void); diff --git a/disk-utils/fdisklabel.c b/disk-utils/fdisklabel.c new file mode 100644 index 000000000..5fbf67a4c --- /dev/null +++ b/disk-utils/fdisklabel.c @@ -0,0 +1,801 @@ +/* + NetBSD disklabel editor for Linux fdisk + Written by Bernhard Fastenrath (fasten@informatik.uni-bonn.de) + with code from the NetBSD disklabel command: + + Copyright (c) 1987, 1988 Regents of the University of California. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the University of + California, Berkeley and its contributors. + 4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. +*/ + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <ctype.h> +#include <setjmp.h> +#include <errno.h> + +#include <sys/ioctl.h> +#include <sys/param.h> + +#include <linux/genhd.h> +#include <linux/hdreg.h> +#include <linux/fs.h> + +#include "fdisk.h" +#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 sync_disks (void); +#if defined (i386) +static int bsd_translate_fstype (int linux_type); +static void bsd_link_part (void); +#endif +#if defined (__alpha__) +void alpha_bootblock_checksum (char *boot); +#endif + +static struct disklabel bsd_dlabel; +static char buffer[BSD_BBSIZE]; +#if defined (i386) +static struct partition *bsd_part; +static int bsd_part_index; +#endif + +void +bmenu (void) +{ + puts ("Command action\n" + " d delete a BSD partition\n" + " e edit drive data\n" + " i install bootstrap\n" + " l list known filesystem types\n" + " m print this menu\n" + " n add a new BSD partition\n" + " p print BSD partition table\n" + " q quit without saving changes\n" +#if defined (i386) + " r return to main menu\n" +#endif + " s show complete disklabel\n" + " t change a partition's filesystem id\n" + " w write disklabel to disk\n" +#if defined (i386) + " x link BSD partition to non-BSD partition" +#endif + ); +} + +void +bselect (void) +{ +#if defined (i386) + int t; + + 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) + { + 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) + return; + break; + } + + if (t == 4) + { + printf ("There is no NetBSD partition on %s.\n", disk_device); + return; + } + +#elif defined (__alpha__) + + if (bsd_readlabel (NULL, &bsd_dlabel) == 0) + if (bsd_create_disklabel () == 0) + exit ( EXIT_SUCCESS ); + +#endif + + while (1) + { + putchar ('\n'); + switch (tolower (read_char ("BSD disklabel command (m for help): "))) + { + case 'd': + bsd_delete_part (); + break; + case 'e': + bsd_edit_disklabel (); + break; + case 'i': + bsd_write_bootstrap (); + break; + case 'l': + bsd_list_types (); + break; + case 'n': + bsd_new_part (); + break; + case 'p': + bsd_print_disklabel (0); + break; + case 'q': + close (fd); + exit ( EXIT_SUCCESS ); + case 's': + bsd_print_disklabel (1); + break; + case 't': + bsd_change_fstype (); + break; + case 'w': + bsd_write_disklabel (); + break; +#if defined (i386) + case 'r': + return; + case 'x': + bsd_link_part (); + break; +#endif + default: + bmenu (); + break; + } + } +} + +static void +bsd_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--; +} + +static void +bsd_new_part (void) +{ + uint begin, end; + char mesg[48]; + int i; + + if (!bsd_check_new_partition (&i)) + return; + +#if defined (i386) + begin = bsd_part -> start_sect; + end = begin + bsd_part -> nr_sects - 1; +#elif defined (__alpha__) + begin = 0; + end = bsd_dlabel.d_secperunit; +#endif + + sprintf (mesg, "First %s", str_units()); + begin = read_int (cround (begin), cround (begin), cround (end), ignore, mesg); + + sprintf (mesg, "Last %s or +size or +sizeM or +sizeK", str_units()); + end = read_int (cround (begin), cround (end), cround (end), ignore, mesg); + + if (unit_flag) + { + 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; +} + +static void +bsd_print_disklabel (int show_all) +{ + struct disklabel *lp = &bsd_dlabel; + struct bsd_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); +#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]); + 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, "flags:"); + if (lp->d_flags & BSD_D_REMOVABLE) + fprintf(f, " removable"); + if (lp->d_flags & BSD_D_ECC) + fprintf(f, " ecc"); + 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); + 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, "drivedata: "); + for (i = NDDATA - 1; i >= 0; i--) + if (lp->d_drivedata[i]) + break; + if (i < 0) + i = 0; + for (j = 0; j <= i; j++) + fprintf(f, "%d ", 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); + if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES) + fprintf(f, "%8.8s", bsd_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, ""); + break; + + case BSD_FS_BSDFFS: + fprintf(f, " %5d %5d %5d ", + pp->p_fsize, pp->p_fsize * pp->p_frag, + pp->p_cpg); + break; + + default: + fprintf(f, "%20.20s", ""); + break; + } + fprintf(f, "\t# (Cyl. %4d", +#if 0 + pp->p_offset / lp->d_secpercyl); /* differs from Linux fdisk */ +#else + pp->p_offset / lp->d_secpercyl + 1); +#endif + if (pp->p_offset % lp->d_secpercyl) + putc('*', f); + else + putc(' ', f); + fprintf(f, "- %d", + (pp->p_offset + + pp->p_size + lp->d_secpercyl - 1) / +#if 0 + lp->d_secpercyl - 1); /* differs from Linux fdisk */ +#else + lp->d_secpercyl); +#endif + if (pp->p_size % lp->d_secpercyl) + putc('*', f); + fprintf(f, ")\n"); + } + } +} + +static void +bsd_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); +#elif defined (__alpha__) + printf ("Writing disklabel to %s.\n", disk_device); + bsd_writelabel (NULL, &bsd_dlabel); +#endif +} + +static int +bsd_create_disklabel (void) +{ + char c; + +#if defined (i386) + fprintf (stderr, "%s%d contains no disklabel.\n", + disk_device, bsd_part_index+1); +#elif defined (__alpha__) + fprintf (stderr, "%s contains no disklabel.\n", disk_device); +#endif + + while (1) + 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) +#elif defined (__alpha__) + if (bsd_initlabel (NULL, &bsd_dlabel, 0) == 1) +#endif + { + bsd_print_disklabel (1); + return 1; + } + else + return 0; + } + else if (c == 'n') + return 0; +} + +static int +edit_int (int def, char *mesg) +{ + do { + fputs (mesg, stdout); + printf (" (%d): ", def); + if (!read_line ()) + return def; + } + while (!isdigit (*line_ptr)); + return atoi (line_ptr); +} + +static void +bsd_edit_disklabel (void) +{ + struct disklabel *d; + + d = &bsd_dlabel; + +#ifdef __alpha__ + d -> d_secsize = (u_long) edit_int ((u_long) d -> d_secsize ,"bytes/sector"); + d -> d_nsectors = (u_long) edit_int ((u_long) d -> d_nsectors ,"sectors/track"); + d -> d_ntracks = (u_long) edit_int ((u_long) d -> d_ntracks ,"tracks/cylinder"); + d -> d_ncylinders = (u_long) edit_int ((u_long) d -> d_ncylinders ,"cylinders"); +#endif + + /* d -> d_secpercyl can be != d -> d_nsectors * d -> d_ntracks */ + while (1) + { + d -> d_secpercyl = (u_long) edit_int ((u_long) d -> d_nsectors * d -> d_ntracks, + "sectors/cylinder"); + if (d -> d_secpercyl <= d -> d_nsectors * d -> d_ntracks) + break; + + printf ("Must be <= sectors/track * tracks/cylinder (default).\n"); + } + d -> d_rpm = (u_short) edit_int ((u_short) d -> d_rpm ,"rpm"); + d -> d_interleave = (u_short) edit_int ((u_short) d -> d_interleave,"interleave"); + d -> d_trackskew = (u_short) edit_int ((u_short) d -> d_trackskew ,"trackskew"); + d -> d_cylskew = (u_short) edit_int ((u_short) d -> d_cylskew ,"cylinderskew"); + d -> d_headswitch = (u_long) edit_int ((u_long) d -> d_headswitch ,"headswitch"); + d -> d_trkseek = (u_long) edit_int ((u_long) d -> d_trkseek ,"track-to-track seek"); + + d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders; +} + +static int +bsd_get_bootstrap (char *path, void *ptr, int size) +{ + int fd; + + if ((fd = open (path, O_RDONLY)) < 0) + { + perror (path); + return 0; + } + if (read (fd, ptr, size) < 0) + { + perror (path); + close (fd); + return 0; + } + printf (" ... %s\n", path); + close (fd); + return 1; +} + +static void +bsd_write_bootstrap (void) +{ + char *bootdir = BSD_LINUX_BOOTDIR; + char path[MAXPATHLEN]; + char *dkbasename; + struct disklabel dl; + char *d, *p, *e; + int sector; + + if (bsd_dlabel.d_type == BSD_DTYPE_SCSI) + dkbasename = "sd"; + else + dkbasename = "wd"; + + printf ("Bootstrap: %sboot -> boot%s (%s): ", dkbasename, dkbasename, dkbasename); + if (read_line ()) + { + line_ptr[strlen (line_ptr)-1] = '\0'; + dkbasename = line_ptr; + } + sprintf (path, "%s/%sboot", bootdir, dkbasename); + if (!bsd_get_bootstrap (path, buffer, (int) bsd_dlabel.d_secsize)) + return; + + /* We need a backup of the disklabel (bsd_dlabel might have changed). */ + d = &buffer[BSD_LABELSECTOR * SECTOR_SIZE]; + bcopy (d, &dl, sizeof (struct disklabel)); + + /* The disklabel will be overwritten by 0's from bootxx anyway */ + bzero (d, sizeof (struct 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)) + return; + + e = d + sizeof (struct disklabel); + for (p=d; p < e; p++) + if (*p) + { + fprintf (stderr, "Bootstrap overlaps with disk label!\n"); + exit ( EXIT_FAILURE ); + } + + bcopy (&dl, d, sizeof (struct disklabel)); + +#if defined (i386) + sector = bsd_part -> start_sect; +#elif defined (__alpha__) + sector = 0; + alpha_bootblock_checksum (buffer); +#endif + + if (ext2_llseek (fd, sector * SECTOR_SIZE, SEEK_SET) == -1) + fatal (unable_to_seek); + if (BSD_BBSIZE != write (fd, buffer, BSD_BBSIZE)) + fatal (unable_to_write); + +#if defined (i386) + printf ("Bootstrap installed on %s%d.\n", disk_device, bsd_part_index+1); +#elif defined (__alpha__) + printf ("Bootstrap installed on %s.\n", disk_device); +#endif + + sync_disks (); +} + +static void +bsd_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); +} + +static int +bsd_get_part_index (int max) +{ + char prompt[40]; + char l; + + sprintf (prompt, "Partition (a-%c): ", 'a' + max - 1); + do + l = tolower (read_char (prompt)); + while (l < 'a' || l > 'a' + max - 1); + return l - 'a'; +} + +static int +bsd_check_new_partition (int *i) +{ + int t; + + if (bsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) + { + for (t=0; t < BSD_MAXPARTITIONS; t++) + if (bsd_dlabel.d_partitions[t].p_size == 0) + break; + + if (t == BSD_MAXPARTITIONS) + { + fprintf (stderr, "The maximum number of partitions has been created\n"); + return 0; + } + } + *i = bsd_get_part_index (BSD_MAXPARTITIONS); + + if (*i >= bsd_dlabel.d_npartitions) + bsd_dlabel.d_npartitions = (*i) + 1; + + if (bsd_dlabel.d_partitions[*i].p_size != 0) + { + fprintf (stderr, "This partition already exists.\n"); + return 0; + } + return 1; +} + +static void +bsd_list_types (void) +{ + list_types (bsd_fstypes, BSD_FSMAXTYPES); +} + +static u_short +bsd_dkcksum (struct disklabel *lp) +{ + register u_short *start, *end; + register u_short sum = 0; + + start = (u_short *)lp; + end = (u_short *)&lp->d_partitions[lp->d_npartitions]; + while (start < end) + sum ^= *start++; + return (sum); +} + +static int +bsd_initlabel (struct partition *p, struct disklabel *d, int pindex) +{ + struct hd_geometry geometry; + struct bsd_partition *pp; + + if (ioctl (fd, HDIO_GETGEO, &geometry) == -1) + { + perror ("ioctl"); + return 0; + } + bzero (d, sizeof (struct disklabel)); + + d -> d_magic = BSD_DISKMAGIC; + + if (strncmp (disk_device, "/dev/sd", 7) == 0) + d -> d_type = BSD_DTYPE_SCSI; + else + d -> d_type = BSD_DTYPE_ST506; + +#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */ + d -> d_subtype = BSD_DSTYPE_INDOSPART & pindex; +#endif + +#if defined (i386) + d -> d_flags = BSD_D_DOSPART; +#else + d -> d_flags = 0; +#endif + d -> d_secsize = SECTOR_SIZE; /* bytes/sector */ + d -> d_nsectors = geometry.sectors; /* sectors/track */ + d -> d_ntracks = geometry.heads; /* tracks/cylinder (heads) */ + d -> d_ncylinders = geometry.cylinders; + d -> d_secpercyl = geometry.sectors * geometry.heads; /* sectors/cylinder */ + d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders; + + d -> d_rpm = 3600; + d -> d_interleave = 1; + d -> d_trackskew = 0; + d -> d_cylskew = 0; + d -> d_headswitch = 0; + d -> d_trkseek = 0; + + d -> d_magic2 = BSD_DISKMAGIC; + d -> d_bbsize = BSD_BBSIZE; + d -> d_sbsize = BSD_SBSIZE; + +#if defined (i386) + d -> d_npartitions = 4; + pp = &d -> d_partitions[2]; /* Partition C should be the NetBSD partition */ + pp -> p_offset = p -> start_sect; + pp -> p_size = p -> nr_sects; + pp -> p_fstype = BSD_FS_UNUSED; + pp = &d -> d_partitions[3]; /* Partition D should be the whole disk */ + pp -> p_offset = 0; + pp -> p_size = d -> d_secperunit; + pp -> p_fstype = BSD_FS_UNUSED; +#elif defined (__alpha__) + d -> d_npartitions = 3; + pp = &d -> d_partitions[2]; /* Partition C should be the whole disk */ + pp -> p_offset = 0; + pp -> p_size = d -> d_secperunit; + pp -> p_fstype = BSD_FS_UNUSED; +#endif + + return 1; +} + +static int +bsd_readlabel (struct partition *p, struct disklabel *d) +{ + int t, sector; + +#if defined (i386) + sector = p -> start_sect; +#elif defined (__alpha__) + sector = 0; +#endif + + if (ext2_llseek (fd, sector * SECTOR_SIZE, SEEK_SET) == -1) + fatal (unable_to_seek); + if (BSD_BBSIZE != read (fd, buffer, BSD_BBSIZE)) + fatal (unable_to_read); + + bcopy (&buffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET], + d, sizeof (struct disklabel)); + + for (t = d -> d_npartitions; t < BSD_MAXPARTITIONS; t++) + { + d -> d_partitions[t].p_size = 0; + d -> d_partitions[t].p_offset = 0; + d -> d_partitions[t].p_fstype = BSD_FS_UNUSED; + } + if (d -> d_magic != BSD_DISKMAGIC || d -> d_magic2 != BSD_DISKMAGIC) + return 0; + + if (d -> d_npartitions > BSD_MAXPARTITIONS) + fprintf (stderr, "Warning: too many partitions (%d, maximum is %d).\n", + d -> d_npartitions, BSD_MAXPARTITIONS); + return 1; +} + +static int +bsd_writelabel (struct partition *p, struct disklabel *d) +{ + int sector; + +#if defined (i386) + sector = p -> start_sect + BSD_LABELSECTOR; +#elif defined (__alpha__) + sector = BSD_LABELSECTOR; +#endif + + d -> d_checksum = 0; + d -> d_checksum = bsd_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)); + +#if defined (__alpha__) && BSD_LABELSECTOR == 0 + alpha_bootblock_checksum (buffer); + if (ext2_llseek (fd, 0, SEEK_SET) == -1) + fatal (unable_to_seek); + if (BSD_BBSIZE != write (fd, buffer, BSD_BBSIZE)) + fatal (unable_to_write); +#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))) + fatal (unable_to_write); +#endif + + sync_disks (); + + return 1; +} + +static void +sync_disks (void) +{ + printf ("\nSyncing disks.\n"); + sync (); + sleep (4); +} + +#if defined (i386) +static int +bsd_translate_fstype (int linux_type) +{ + switch (linux_type) + { + case 0x01: /* DOS 12-bit FAT */ + case 0x04: /* DOS 16-bit <32M */ + case 0x06: /* DOS 16-bit >=32M */ + case 0xe1: /* DOS access */ + case 0xe3: /* DOS R/O */ + case 0xf2: /* DOS secondary */ + return BSD_FS_MSDOS; + case 0x07: /* OS/2 HPFS */ + return BSD_FS_HPFS; + default: + return BSD_FS_OTHER; + } +} + +static void +bsd_link_part (void) +{ + int k, i; + + k = get_partition (1, partitions); + + if (!bsd_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); +} +#endif + +#if defined (__alpha__) +typedef unsigned long long u_int64_t; + +void +alpha_bootblock_checksum (char *boot) +{ + u_int64_t *dp, sum; + int i; + + dp = (u_int64_t *)boot; + sum = 0; + for (i = 0; i < 63; i++) + sum += dp[i]; + dp[63] = sum; +} +#endif /* __alpha__ */ diff --git a/disk-utils/fdisklabel.h b/disk-utils/fdisklabel.h new file mode 100644 index 000000000..841046bb8 --- /dev/null +++ b/disk-utils/fdisklabel.h @@ -0,0 +1,233 @@ +/* + * Copyright (c) 1987, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define BSD_DISKMAGIC ((u_long) 0x82564557) +#define BSD_MAXPARTITIONS 8 +#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec" + +#if defined (i386) +#define BSD_LABELSECTOR 1 +#define BSD_LABELOFFSET 0 +#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 +#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 */ + 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 */ + /* + * 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 */ + /* + * Alternate cylinders include maintenance, replacement, + * configuration description areas, etc. + */ + u_long d_acylinders; /* # of alt. cylinders per unit */ + + /* hardware characteristics: */ + /* + * d_interleave, d_trackskew and d_cylskew describe perturbations + * in the media format used to compensate for a slow controller. + * Interleave is physical sector interleave, set up by the formatter + * or controller when formatting. When interleaving is in use, + * logically adjacent sectors are not physically contiguous, + * but instead are separated by some number of sectors. + * It is specified as the ratio of physical sectors traversed + * per logical sector. Thus an interleave of 1:1 implies contiguous + * layout, while 2:1 implies that logical sector 0 is separated + * by one sector from logical sector 1. + * d_trackskew is the offset of sector 0 on track N + * relative to sector 0 on track N-1 on the same cylinder. + * 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 */ +#define NDDATA 5 + u_long 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 */ + /* 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 */ + } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */ +}; + +/* d_type values: */ +#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */ +#define BSD_DTYPE_MSCP 2 /* MSCP */ +#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */ +#define BSD_DTYPE_SCSI 4 /* SCSI */ +#define BSD_DTYPE_ESDI 5 /* ESDI interface */ +#define BSD_DTYPE_ST506 6 /* ST506 etc. */ +#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */ +#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */ +#define BSD_DTYPE_FLOPPY 10 /* floppy */ + +/* d_subtype values: */ +#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */ +#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */ +#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */ + +#ifdef DKTYPENAMES +static char *bsd_dktypenames[] = { + "unknown", + "SMD", + "MSCP", + "old DEC", + "SCSI", + "ESDI", + "ST506", + "HP-IB", + "HP-FL", + "type 9", + "floppy", + 0 +}; +#define BSD_DKMAXTYPES (sizeof(bsd_dktypenames) / sizeof(bsd_dktypenames[0]) - 1) +#endif + +/* + * Filesystem type and version. + * Used to interpret other filesystem-specific + * per-partition information. + */ +#define BSD_FS_UNUSED 0 /* unused */ +#define BSD_FS_SWAP 1 /* swap */ +#define BSD_FS_V6 2 /* Sixth Edition */ +#define BSD_FS_V7 3 /* Seventh Edition */ +#define BSD_FS_SYSV 4 /* System V */ +#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 */ +#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */ +#define BSD_FS_ISOFS BSD_FS_ISO9660 +#define BSD_FS_BOOT 13 /* partition contains bootstrap */ +#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */ +#define BSD_FS_HFS 15 /* Macintosh HFS */ + +#ifdef DKTYPENAMES +static struct systypes bsd_fstypes[] = { + {BSD_FS_UNUSED, "unused"}, + {BSD_FS_SWAP, "swap"}, + {BSD_FS_V6, "Version 6"}, + {BSD_FS_V7, "Version 7"}, + {BSD_FS_SYSV, "System V"}, + {BSD_FS_V71K, "4.1BSD"}, + {BSD_FS_V8, "Eighth Edition"}, + {BSD_FS_BSDFFS, "4.2BSD"}, + {BSD_FS_MSDOS, "MS-DOS"}, + {BSD_FS_BSDLFS, "4.4LFS"}, + {BSD_FS_OTHER, "unknown"}, + {BSD_FS_HPFS, "HPFS"}, + {BSD_FS_ISO9660,"ISO-9660"}, + {BSD_FS_BOOT, "boot"}, + {BSD_FS_ADOS, "ADOS"}, + {BSD_FS_HFS, "HFS"} +}; + +#define BSD_FSMAXTYPES (sizeof(bsd_fstypes) / sizeof(struct systypes)) +#endif + +/* + * flags shared by various drives: + */ +#define BSD_D_REMOVABLE 0x01 /* removable media */ +#define BSD_D_ECC 0x02 /* supports ECC */ +#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */ +#define BSD_D_RAMDISK 0x08 /* disk emulator */ +#define BSD_D_CHAIN 0x10 /* can do back-back transfers */ +#define BSD_D_DOSPART 0x20 /* within MSDOS partition */ diff --git a/disk-utils/fsck.minix.8 b/disk-utils/fsck.minix.8 index 32bbe4881..024e1b7a3 100644 --- a/disk-utils/fsck.minix.8 +++ b/disk-utils/fsck.minix.8 @@ -123,3 +123,6 @@ Error code values by Rik Faith (faith@cs.unc.edu) .br Added support for file system valid flag: Dr. Wettstein (greg%wind.uucp@plains.nodak.edu) +.br +Check to prevent fsck of mounted filesystem added by Daniel Quinlan +(quinlan@yggdrasil.com) diff --git a/disk-utils/llseek.c b/disk-utils/llseek.c index 66166d3a8..3e59ec953 100644 --- a/disk-utils/llseek.c +++ b/disk-utils/llseek.c @@ -5,16 +5,19 @@ * under the terms of the GNU Public License. */ +#define FOR_UTIL_LINUX + #include <sys/types.h> #include <errno.h> #include <unistd.h> #include <linux/unistd.h> -#if 0 +#ifndef FOR_UTIL_LINUX #include "et/com_err.h" #include "ext2fs/io.h" #endif +#ifdef FOR_UTIL_LINUX #if defined(__GNUC__) || defined(HAS_LONG_LONG) typedef long long ext2_loff_t; #else @@ -24,6 +27,7 @@ typedef long ext2_loff_t; extern ext2_loff_t ext2_llseek(unsigned int fd, ext2_loff_t offset, unsigned int origin); +#endif #ifdef __linux__ @@ -47,8 +51,15 @@ ext2_loff_t ext2_llseek (unsigned int fd, ext2_loff_t offset, int retval; static int do_compat = 0; - if (do_compat) + 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); + } offset_high = ((unsigned long long) offset) >> 32; offset_low = ((unsigned long long) offset) & 0xffffffff; @@ -59,7 +70,7 @@ ext2_loff_t ext2_llseek (unsigned int fd, ext2_loff_t offset, * which does not support the llseek system call */ do_compat++; - return lseek (fd, (off_t) offset, origin); + goto compat_lseek; } if (retval == -1) result = -1; diff --git a/disk-utils/mkfs.8 b/disk-utils/mkfs.8 index 48b223425..e391f7141 100644 --- a/disk-utils/mkfs.8 +++ b/disk-utils/mkfs.8 @@ -1,12 +1,9 @@ .\" -*- nroff -*- -.TH FSCK 8 "Jul 1993" "Version 1.8" +.TH MKFS 8 "Jun 1995" "Version 1.9" .SH NAME -fsck \- check and repair a Linux file system +mkfs \- build a Linux file system .SH SYNOPSIS -.B fsck -[ -.B \-A -] +.B mkfs [ .B \-V ] @@ -18,62 +15,35 @@ fsck \- check and repair a Linux file system .B fs-options ] .I filesys +[ +.I blocks +] .SH DESCRIPTION -.B fsck -is used to check and optionally repair a Linux file system. +.B mkfs +is used to build a Linux file system on a device, usually +a hard disk partition. .I filesys is either the device name (e.g. /dev/hda1, /dev/sdb2) or the mount point (e.g. /, /usr, /home) for the file system. +.I blocks +is the number of blocks to be used for the file system. .PP The exit code returned by -.B fsck -is the sum of the following conditions: -.br -\ 0\ \-\ No errors -.br -\ 1\ \-\ File system errors corrected -.br -\ 2\ \-\ File system errors corrected, system should -.br -\ \ \ \ be rebooted if file system was mounted -.br -\ 4\ \-\ File system errors left uncorrected -.br -\ 8\ \-\ Operational error -.br -\ 16\ \-\ Usage or syntax error -.br -\ 128\ \-\ Shared library error -.br -The exit code returned when all file systems are checked using the -.B -A -option is the bit-wise OR of the exit codes for each -file system that is checked. +.B mkfs +is 0 on success and 1 on failure. .PP In actuality, -.B fsck -is simply a front-end for the various file system checkers -(\fBfsck\fR.\fIfstype\fR) +.B mkfs +is simply a front-end for the various file system builders +(\fBmkfs\fR.\fIfstype\fR) available under Linux. -The file system-specific checker is searched for in /etc/fs first, +The file system-specific builder is searched for in /etc/fs first, then in /etc and finally in the directories listed in the PATH -environment variable. -Please see the file system-specific checker manual pages for +enviroment variable. +Please see the file system-specific builder manual pages for further details. .SH OPTIONS .TP -.B -A -Walk through the -.I /etc/fstab -file and try to check all file systems in one run. This option is -typically used from the -.I /etc/rc -system initalization file, instead of multiple commands for checking -a single file system. Note, that with this option, you cannot give -the -.I filesys -argument as well. -.TP .B -V Produce verbose output, including all file system-specific commands that are executed. @@ -82,7 +52,7 @@ file system-specific commands. This is really only useful for testing. .TP .BI -t \ fstype -Specifies the type of file system to be checked. +Specifies the type of file system to be built. If not specified, the type is deduced by searching for .I filesys in @@ -93,24 +63,18 @@ If the type can not be deduced, the default file system type .TP .B fs-options File system-specific options to be passed to the real file -system checker. +system builder. Although not guaranteed, the following options are supported -by most file system checkers. -.TP -.I -a -Automatically repair the file system without any questions (use -this option with caution). -.TP -.I -l -List all the file names in the file system. +by most file system builders. .TP -.I -r -Interactively repair the file system (ask for confirmations). +.B -c +Check the device for bad blocks before building the file system. .TP -.I -s -List the super block before checking the file system. +.BI -l \ filename +Read the bad blocks list from +.I filename .TP -.I -v +.B -v Produce verbose output. .SH BUGS All generic options must precede and not be combined with @@ -118,16 +82,22 @@ file system-specific options. Some file system-specific programs do not support the .I -v (verbose) option, nor return meaningful exit codes. +Also, some file system-specific programs do not automatically +detect the device size and require the +.I blocks +parameter to be specified. .SH AUTHORS David Engel (david@ods.com) .br Fred N. van Kempen (waltje@uwalt.nl.mugnet.org) .br +Ron Sommeling (sommel@sci.kun.nl) +.br The manual page was shamelessly adapted from Remy Card's version for the ext2 file system. .SH SEE ALSO -.BR mkfs (8), -.BR fsck.minix (8), -.BR fsck.ext (8), -.BR fsck.ext2 (8), -.BR fsck.xiafs (8). +.BR fsck (8), +.BR mkfs.minix (8), +.BR mkfs.ext (8), +.BR mkfs.ext2 (8), +.BR mkfs.xiafs (8). diff --git a/disk-utils/mkfs.c b/disk-utils/mkfs.c index 018a53849..78a3a0c2f 100644 --- a/disk-utils/mkfs.c +++ b/disk-utils/mkfs.c @@ -1,297 +1,79 @@ /* - * fs-util A simple generic frontend for the for the fsck and mkfs - * programs under Linux. See the manual pages for details. + * mkfs A simple generic frontend for the for the mkfs program + * under Linux. See the manual page for details. * - * Usage: fsck [-AV] [-t fstype] [fs-options] device - * mkfs [-V] [-t fstype] [fs-options] device< [size] + * Usage: mkfs [-V] [-t fstype] [fs-options] device [size] * * Authors: David Engel, <david@ods.com> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * Ron Sommeling, <sommel@sci.kun.nl> */ -#include <sys/types.h> -#include <sys/wait.h> -#include <errno.h> -#include <limits.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <mntent.h> #include <unistd.h> #include <getopt.h> +#include <limits.h> +#define VERSION "1.9" + #ifndef DEFAULT_FSTYPE -# define DEFAULT_FSTYPE "minix" +# define DEFAULT_FSTYPE "minix" #endif -#define _PATH_PROG "%s.%s" -#define _PROG_FSCK "fsck" - -#define EXIT_OK 0 -#define EXIT_NONDESTRUCT 1 -#define EXIT_DESTRUCT 2 -#define EXIT_UNCORRECTED 4 -#define EXIT_ERROR 8 -#define EXIT_USAGE 16 -#define EXIT_LIBRARY 128 - -static char *Version = "1.8"; -static char *ignored_types[] = { - "ignore", - "iso9660", - "msdos", - "nfs", - "proc", - "sw", - "swap", - NULL -}; - - -/* Execute a program. */ -int do_exec(char *prog, char **argv, int verbose) -{ - char *args[33]; - register int i; - int pid, status; - - /* Build the vector. */ - i = 0; - args[i++] = prog; - while(*argv != NULL && i < 32) - args[i++] = *argv++; - args[i] = NULL; - - if (verbose) { - i = 0; - while(args[i] != NULL) { - printf("%s ", args[i]); - i++; - } - printf("\n"); - if (verbose > 1) - return EXIT_OK; - } - - /* Fork and execute the correct program. */ - if ((pid = fork()) < 0) { - perror("fork"); - status = EXIT_ERROR; - } else if (pid == 0) { - (void) execvp(args[0], args); - perror(args[0]); - exit(EXIT_ERROR); - } else { - while(wait(&status) != pid) - ; - status = WEXITSTATUS(status); - } - - return status; -} - - -/* Check if we have to ignore a file system type. */ -int ignore(char *type, char *opts) -{ - char *cp; - char **ip; - - ip = ignored_types; - while (*ip != NULL) { - if (!strcmp(type, *ip)) - return 1; - ip++; - } - - for (cp = strtok(opts, ","); cp != NULL; cp = strtok(NULL, ",")) { - if (!strcmp(cp, "noauto")) - return 1; - } - - return 0; -} - - -/* Check all file systems, using the /etc/fstab table. */ -int check_all(int verbose, char **argv) -{ - char path[PATH_MAX]; - char *args[33]; - FILE *mntfile; - struct mntent *mp; - register int i; - int status = EXIT_OK; - - if (verbose) - printf("Checking all file systems.\n"); - - /* Create an array of arguments. */ - i = 0; - while (*argv != NULL && i < 32) - args[i++] = *argv++; - args[i] = NULL; - args[i + 1] = NULL; - - /* Open the mount table. */ - if ((mntfile = setmntent(MNTTAB, "r")) == NULL) { - perror(MNTTAB); - exit(EXIT_ERROR); - } - - /* Walk through the /etc/fstab file. */ - while ((mp = getmntent(mntfile)) != NULL) { - if (verbose) - printf("%-7s %-15s %-15s ", mp->mnt_type, - mp->mnt_fsname, mp->mnt_dir); - if (ignore(mp->mnt_type, mp->mnt_opts)) { - if (verbose) - printf("(ignored)\n"); - continue; - } - - /* Build program name. */ - sprintf(path, _PATH_PROG, _PROG_FSCK, mp->mnt_type); - args[i] = mp->mnt_fsname; - status |= do_exec(path, args, verbose); - } - - (void) endmntent(mntfile); - - return status; -} - - -/* Lookup filesys in /etc/fstab and return the corresponding entry. */ -struct mntent *lookup(char *filesys) -{ - FILE *mntfile; - struct mntent *mp; - - /* No filesys name given. */ - if (filesys == NULL) - return NULL; - - /* Open the mount table. */ - if ((mntfile = setmntent(MNTTAB, "r")) == NULL) { - perror(MNTTAB); - exit(EXIT_ERROR); - } - - while ((mp = getmntent(mntfile)) != NULL) { - if (!strcmp(filesys, mp->mnt_fsname) || - !strcmp(filesys, mp->mnt_dir)) - break; - } +#define SEARCH_PATH "PATH=/sbin:/sbin/fs.d:/sbin/fs:/etc/fs:/etc" +#define PROGNAME "mkfs.%s" - (void) endmntent(mntfile); - return mp; -} - - -void usage(int fsck, char *prog) +int main(int argc, char *argv[]) { - if (fsck) { - fprintf(stderr, "Usage: fsck [-AV] [-t fstype] [fs-options] filesys\n"); - } else { - fprintf(stderr, "Usage: mkfs [-V] [-t fstype] [fs-options] filesys [size]\n"); - } - - exit(EXIT_USAGE); -} - - -void main(int argc, char *argv[]) -{ - char path[PATH_MAX]; - char *oldpath, newpath[PATH_MAX]; - register char *sp; - struct mntent *fsent; - char *fstype = NULL; - int verbose = 0; - int doall = 0; - int i, fsck, more; - - /* Must be 1 for "fsck" and 0 for "mkfs". */ - if ((sp = strrchr(argv[0], '/')) != NULL) - sp++; - else - sp = argv[0]; - if (!strcmp(sp, _PROG_FSCK)) - fsck = 1; - else - fsck = 0; - - /* Check commandline options. */ - opterr = 0; - more = 0; - while ((more == 0) && ((i = getopt(argc, argv, "AVt:")) != EOF)) - switch(i) { - case 'A': - doall++; - break; - case 'V': - verbose++; - break; - case 't': - if (optarg == NULL) - usage(fsck, sp); - fstype = optarg; - break; - default: - more = 1; - break; /* start of specific arguments */ - } - - /* Did we get any specific arguments? */ - if (more) - optind--; - - /* Print our version number if requested. */ - if (verbose) - printf("%s (fsutil) version %s (%s)\n", argv[0], - Version, __DATE__); - - /* Update our PATH to include /etc/fs and /etc. */ - strcpy(newpath, "PATH=/etc/fs:/etc:"); - if ((oldpath = getenv("PATH")) != NULL) - strcat(newpath, oldpath); - putenv(newpath); - - /* If -A was specified ("check all"), double-check. */ - if (doall) { - if (!fsck || (fstype != NULL)) - usage(fsck, sp); - exit(check_all(verbose, &argv[optind])); - } else { - /* If -t wasn't specified, we must deduce fstype. */ - if (fstype == NULL) { - /* make sure that "filesys" was specified */ - if (optind >= argc) - usage(fsck, sp); - /* then try looking for it in /etc/fstab */ - if ((fsent = lookup(argv[argc - 1])) != NULL) { - argv[argc - 1] = fsent->mnt_fsname; - fstype = fsent->mnt_type; - } else { - if (!fsck && optind < argc-1) { - if ((fsent = lookup(argv[argc - 2])) != NULL) { - argv[argc - 2] = fsent->mnt_fsname; - fstype = fsent->mnt_type; - } - } - } - /* if we still don't know, use the default */ - if (fstype == NULL) fstype = DEFAULT_FSTYPE; - } - - /* Build program name. */ - sprintf(path, _PATH_PROG, sp, fstype); - exit(do_exec(path, &argv[optind], verbose)); + char progname[NAME_MAX]; + char *fstype = NULL; + int i, more = 0, verbose = 0; + + /* Check commandline options. */ + opterr = 0; + while ((more == 0) && ((i = getopt(argc, argv, "Vt:")) != EOF)) + switch (i) { + case 'V': + verbose++; + break; + case 't': + fstype = optarg; + break; + default: + more = 1; + break; /* start of specific arguments */ } - /*NOTREACHED*/ + if (optind == argc) { + fprintf(stderr, + "Usage: mkfs [-V] [-t fstype] [fs-options] device [size]\n"); + return -1; + } + + /* If -t wasn't specified, use the default */ + if (fstype == NULL) + fstype = DEFAULT_FSTYPE; + + /* Set PATH and program name */ + putenv(SEARCH_PATH); + sprintf(progname, PROGNAME, fstype); + argv[--optind] = progname; + + if (verbose) { + puts("mkfs version " VERSION " (" __DATE__ ")"); + i = optind; + while (argv[i]) + printf("%s ", argv[i++]); + printf("\n"); + if (verbose > 1) + return 0; + } + + /* Execute the program */ + execvp(progname, argv+optind); + perror(progname); + return 1; } diff --git a/disk-utils/mkfs.minix.8 b/disk-utils/mkfs.minix.8 index cbfb1cf4c..3c59bb073 100644 --- a/disk-utils/mkfs.minix.8 +++ b/disk-utils/mkfs.minix.8 @@ -86,3 +86,6 @@ Inode request feature by Scott Heavner (sdh@po.cwru.edu) .br Support for the file system valid flag by Dr. Wettstein (greg%wind.uucp@plains.nodak.edu) +.br +Check to prevent mkfs of mounted filesystem and boot sector clearing +by Daniel Quinlan (quinlan@yggdrasil.com) diff --git a/disk-utils/mkfs.minix.c b/disk-utils/mkfs.minix.c index b2dcf7896..87c7c1270 100644 --- a/disk-utils/mkfs.minix.c +++ b/disk-utils/mkfs.minix.c @@ -6,33 +6,39 @@ */ /* - * 24.11.91 - time began. Used the fsck sources to get started. + * DD.MM.YY * - * 25.11.91 - corrected some bugs. Added support for ".badblocks" + * 24.11.91 - Time began. Used the fsck sources to get started. + * + * 25.11.91 - Corrected some bugs. Added support for ".badblocks" * The algorithm for ".badblocks" is a bit weird, but * it should work. Oh, well. * - * 25.01.92 - Added the -l option for getting the list of bad blocks - * out of a named file. (Dave Rivers, rivers@ponds.uucp) + * 25.01.92 - Added the -l option for getting the list of bad blocks + * out of a named file. (Dave Rivers, rivers@ponds.uucp) * - * 28.02.92 - added %-information when using -c. + * 28.02.92 - Added %-information when using -c. * - * 28.02.93 - added support for other namelengths than the original + * 28.02.93 - Added support for other namelengths than the original * 14 characters so that I can test the new kernel routines.. * - * Sat Oct 9 11:48:31 1993, faith@cs.unc.edu: make exit status conform - * to that required by fsutil + * 09.10.93 - Make exit status conform to that required by fsutil + * (Rik Faith, faith@cs.unc.edu) * - * 31.10.93 - added inode request feature, for backup floppies: use - * 32 inodes, for a news partition use more. - * (Scott Heavner, sdh@po.cwru.edu) + * 31.10.93 - Added inode request feature, for backup floppies: use + * 32 inodes, for a news partition use more. + * (Scott Heavner, sdh@po.cwru.edu) * - * Mon Jan 3 11:08:49 1994, Dr. Wettstein (greg%wind.uucp@plains.nodak.edu). - * Added support for file system valid flag. + * 03.01.94 - Added support for file system valid flag. + * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu) * - * 9.11.94 - added test to prevent overwrite of mounted fs adapted - * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs - * program. (Daniel Quinlan, quinlan@yggdrasil.com) + * 09.11.94 - Added test to prevent overwrite of mounted fs adapted + * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs + * program. (Daniel Quinlan, quinlan@yggdrasil.com) + * + * 03.20.95 - Clear first 512 bytes of filesystem to make certain that + * 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 @@ -98,6 +104,7 @@ static char root_block[BLOCK_SIZE] = "\0"; static char * inode_buffer = NULL; #define Inode (((struct minix_inode *) inode_buffer)-1) 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) @@ -181,16 +188,21 @@ void write_tables(void) Super.s_state |= MINIX_VALID_FS; Super.s_state &= ~MINIX_ERROR_FS; + if (lseek(DEV, 0, SEEK_SET)) + die("seek to boot block failed in write_tables"); + if (512 != write(DEV, boot_block_buffer, 512)) + die("unable to clear boot sector"); if (BLOCK_SIZE != lseek(DEV, BLOCK_SIZE, SEEK_SET)) die("seek failed in write_tables"); if (BLOCK_SIZE != write(DEV, super_block_buffer, BLOCK_SIZE)) die("unable to write super-block"); if (IMAPS*BLOCK_SIZE != write(DEV,inode_map,IMAPS*BLOCK_SIZE)) - die("Unable to write inode map"); + die("unable to write inode map"); if (ZMAPS*BLOCK_SIZE != write(DEV,zone_map,ZMAPS*BLOCK_SIZE)) - die("Unable to write zone map"); + die("unable to write zone map"); if (INODE_BUFFER_SIZE != write(DEV,inode_buffer,INODE_BUFFER_SIZE)) - die("Unable to write inodes"); + die("unable to write inodes"); + } void write_block(int blk, char * buffer) @@ -314,6 +326,7 @@ void setup_tables(void) memset(inode_map,0xff,sizeof(inode_map)); memset(zone_map,0xff,sizeof(zone_map)); memset(super_block_buffer,0,BLOCK_SIZE); + memset(boot_block_buffer,0,512); MAGIC = magic; ZONESIZE = 0; MAXSIZE = (7+512+512*512)*1024; @@ -339,7 +352,7 @@ void setup_tables(void) unmark_inode(i); inode_buffer = malloc(INODE_BUFFER_SIZE); if (!inode_buffer) - die("Unable to allocate buffer for inodes"); + die("unable to allocate buffer for inodes"); memset(inode_buffer,0,INODE_BUFFER_SIZE); printf("%d inodes\n",INODES); printf("%d blocks\n",ZONES); @@ -424,7 +437,7 @@ char *filename; listfile=fopen(filename,"r"); if(listfile == (FILE *)NULL) { - die("Can't open file of bad blocks"); + die("can't open file of bad blocks"); } while(!feof(listfile)) { fscanf(listfile,"%d\n", &blockno); @@ -519,7 +532,7 @@ int main(int argc, char ** argv) 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'"); + die("will not try to make filesystem on '%s'"); setup_tables(); if (check) check_blocks(); diff --git a/disk-utils/mkswap.8 b/disk-utils/mkswap.8 index 2c02fbbe0..643d7ba04 100644 --- a/disk-utils/mkswap.8 +++ b/disk-utils/mkswap.8 @@ -7,13 +7,13 @@ .\" " .TH MKSWAP 8 "8 February 1995" "Linux 1.0" "Linux Programmer's Manual" .SH NAME -mkswap \- set up a Linux swap device +mkswap \- set up a Linux swap area .SH SYNOPSIS .B "mkswap [ \-c ]" .IB device " [" size-in-blocks "]" .SH DESCRIPTION .B mkswap -sets up a Linux swap area on a device (usually a disk partition). +sets up a Linux swap area on a device or in a file. The .I device @@ -31,23 +31,45 @@ is usually of the following form: The .I size-in-blocks parameter is the desired size of the file system, in blocks. This -information is determined automatically by mkswap if it is omitted. Block -counts are rounded down to pages of 4 kB each. Only block counts equal to -or greater than 40 and equal to or less than 131072 are allowed. Block -counts greater than 130752 are (silently) rounded down to 130752. +information is determined automatically by +.B mkswap +if it is omitted. Block counts are rounded down so that the total +size is an integer multiple of the machine's page size. Only block +counts in the range MINCOUNT..MAXCOUNT are allowed. If the block count +exceeds the MAXCOUNT, it is truncated to that value and a warning +message is issued. + +The MINCOUNT and MAXCOUNT values for a swap area are: -As Nick Holloway explains, the actual maximum for each swap file/partition -is: .RS -(4096 - 10) * 8 * 4096 = 133890048 bytes = 130752 blocks = 127.6875 Mb +MINCOUNT = 10 * PAGE_SIZE / 1024 +.br +MAXCOUNT = (PAGE_SIZE - 10) * 8 * PAGE_SIZE / 1024 .RE -This is because a single page is used to hold the swap bitmap at the -start of the partition, where each bit is a single 4K page. The reason -for the -10, is that the signature is "SWAP-SPACE" -- 10 characters. -.B mkswap -can also set up swap files, although the file has to be created first. A -sequence of commands similar to the following is reasonable for this +For example, on a machine with 4kB pages (e.g., x86), we get: + +.RS +MINCOUNT = 10 * 4096 / 1024 = 40 +.br +MAXCOUNT = (4096 - 10) * 8 * 4096 / 1024 = 130752 +.RE + +As each block is 1kB large, the swap area in this example could have a +size that is anywhere in the range from 40kB up to 127.6875MB. + +If you don't know the page size that your machine uses, you may be +able to look it up with "cat /proc/cpuinfo". + +The reason for the limit on MAXCOUNT is that a single page is used to +hold the swap bitmap at the start of the swap area, where each bit +represents a single page. The reason for the -10, is that the +signature is "SWAP-SPACE" -- 10 characters. + +To setup a swap file, it is necessary to create that file before +running +.B mkswap . +A sequence of commands similar to the following is reasonable for this purpose: .nf @@ -59,9 +81,7 @@ purpose: .RE .fi -Note that the regular file has to be created before running -.B mkswap -on the file, and that the file must not contain any holes (so, using +Note that a swap file must not contain any holes (so, using .BR cp (1) to create the file is not acceptable). diff --git a/disk-utils/mkswap.c b/disk-utils/mkswap.c index bb4e2249e..fe3f04c11 100644 --- a/disk-utils/mkswap.c +++ b/disk-utils/mkswap.c @@ -28,12 +28,8 @@ #include <linux/mm.h> -#ifndef __GNUC__ -#error "needs gcc for the bitop-__asm__'s" -#endif - #ifndef __linux__ -#define volatile +# define volatile #endif #define TEST_BUFFER_PAGES 8 @@ -45,21 +41,29 @@ static long PAGES = 0; static int check = 0; static int badpages = 0; -static char signature_page[PAGE_SIZE]; +static int signature_page[PAGE_SIZE/sizeof(int)]; -#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; \ +static long bit_test_and_set (unsigned int *addr, unsigned int nr) +{ + unsigned int r, m; + + addr += nr / (8 * sizeof(int)); + r = *addr; + m = 1 << (nr & (8 * sizeof(int) - 1)); + *addr = r | m; + return (r & m) != 0; } -bitop(bit,"") -bitop(setbit,"s") -bitop(clrbit,"r") +static bit_test_and_clear (unsigned int *addr, unsigned int nr) +{ + unsigned int r, m; + + addr += nr / (8 * sizeof(int)); + r = *addr; + m = 1 << (nr & (8 * sizeof(int) - 1)); + *addr = r & ~m; + return (r & m) != 0; +} /* * Volatile to let gcc know that this doesn't return. When trying @@ -84,18 +88,18 @@ void check_blocks(void) current_page = 0; while (current_page < PAGES) { if (!check) { - setbit(signature_page,current_page++); + bit_test_and_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))) { - clrbit(signature_page,current_page++); + bit_test_and_clear(signature_page,current_page++); badpages++; continue; } - setbit(signature_page,current_page++); + bit_test_and_set(signature_page,current_page++); } if (badpages) printf("%d bad page%s\n",badpages,(badpages>1)?"s":""); @@ -165,7 +169,7 @@ int main(int argc, char ** argv) argv++; if (argv[0][0] != '-') if (device_name) { - PAGES = strtol(argv[0],&tmp,0)>>2; + PAGES = strtol(argv[0],&tmp,0)>>(PAGE_SHIFT-10); if (*tmp) usage(); } else @@ -179,14 +183,17 @@ 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 || PAGES<10) { + fprintf(stderr, + "%s: error: swap area needs to be at least %ldkB\n", + program_name, 10 * PAGE_SIZE / 1024); usage(); - if (PAGES > 32688) /* 130752 blocks */ - PAGES=32688; -#if 0 - if (PAGES > 32768) - PAGES=32768; -#endif + } + if (PAGES > 8 * (PAGE_SIZE - 10)) { + PAGES = 8 * (PAGE_SIZE - 10); + fprintf(stderr, "%s: warning: truncating swap area to %ldkB\n", + program_name, PAGES * PAGE_SIZE / 1024); + } DEV = open(device_name,O_RDWR); if (DEV < 0 || fstat(DEV, &statbuf) < 0) { perror(device_name); @@ -197,13 +204,13 @@ int main(int argc, char ** argv) else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) die("Will not try to make swapdevice on '%s'"); check_blocks(); - if (!clrbit(signature_page,0)) + if (!bit_test_and_clear(signature_page,0)) die("fatal: first page unreadable"); goodpages = PAGES - badpages - 1; - if (!goodpages) + if (goodpages <= 0) die("Unable to set up swap-space: unreadable"); printf("Setting up swapspace, size = %d bytes\n",goodpages*PAGE_SIZE); - strncpy(signature_page+PAGE_SIZE-10,"SWAP-SPACE",10); + 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)) |