summaryrefslogtreecommitdiffstats
path: root/disk-utils
diff options
context:
space:
mode:
authorKarel Zak2006-12-07 00:25:33 +0100
committerKarel Zak2006-12-07 00:25:33 +0100
commit726f69e29ca9d4842f3acb20fffd2466fda62c09 (patch)
treeabbc1b6e9bfb0dfe32e81a83648e261ccb2d5a5f /disk-utils
parentImported from util-linux-2.2 tarball. (diff)
downloadkernel-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/Makefile34
-rw-r--r--disk-utils/README.fdisk22
-rw-r--r--disk-utils/README.fdisk.alpha16
-rw-r--r--disk-utils/README.fdisk.bsd28
-rw-r--r--disk-utils/cfdisk.82
-rw-r--r--disk-utils/cfdisk.8.bak407
-rw-r--r--disk-utils/cfdisk.c8
-rw-r--r--disk-utils/cfdisk.c.bak2066
-rw-r--r--disk-utils/cfdisk.c.orig2066
-rw-r--r--disk-utils/fdformat.c2
-rw-r--r--disk-utils/fdisk.82
-rw-r--r--disk-utils/fdisk.c280
-rw-r--r--disk-utils/fdisk.h47
-rw-r--r--disk-utils/fdisklabel.c801
-rw-r--r--disk-utils/fdisklabel.h233
-rw-r--r--disk-utils/fsck.minix.83
-rw-r--r--disk-utils/llseek.c17
-rw-r--r--disk-utils/mkfs.8108
-rw-r--r--disk-utils/mkfs.c332
-rw-r--r--disk-utils/mkfs.minix.83
-rw-r--r--disk-utils/mkfs.minix.c57
-rw-r--r--disk-utils/mkswap.856
-rw-r--r--disk-utils/mkswap.c69
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))