summaryrefslogtreecommitdiffstats
path: root/fdisk
diff options
context:
space:
mode:
authorKarel Zak2006-12-07 00:25:37 +0100
committerKarel Zak2006-12-07 00:25:37 +0100
commit5c36a0eb7cdb0360f9afd5d747c321f423b35984 (patch)
tree147599a77eaff2b5fbc0d389e89d2b51602326c0 /fdisk
parentImported from util-linux-2.8 tarball. (diff)
downloadkernel-qcow2-util-linux-5c36a0eb7cdb0360f9afd5d747c321f423b35984.tar.gz
kernel-qcow2-util-linux-5c36a0eb7cdb0360f9afd5d747c321f423b35984.tar.xz
kernel-qcow2-util-linux-5c36a0eb7cdb0360f9afd5d747c321f423b35984.zip
Imported from util-linux-2.9i tarball.
Diffstat (limited to 'fdisk')
-rw-r--r--fdisk/Makefile68
-rw-r--r--fdisk/README.cfdisk45
-rw-r--r--fdisk/README.fdisk583
-rw-r--r--fdisk/cfdisk.8406
-rw-r--r--fdisk/cfdisk.c2642
-rw-r--r--fdisk/fdisk.8223
-rw-r--r--fdisk/fdisk.c2046
-rw-r--r--fdisk/fdisk.h85
-rw-r--r--fdisk/fdiskaixlabel.c64
-rw-r--r--fdisk/fdiskaixlabel.h34
-rw-r--r--fdisk/fdiskbsdlabel.c825
-rw-r--r--fdisk/fdiskbsdlabel.h229
-rw-r--r--fdisk/fdisksgilabel.c888
-rw-r--r--fdisk/fdisksgilabel.h133
-rw-r--r--fdisk/fdisksunlabel.c690
-rw-r--r--fdisk/fdisksunlabel.h74
-rw-r--r--fdisk/llseek.c102
-rw-r--r--fdisk/sfdisk.8506
-rw-r--r--fdisk/sfdisk.c2864
-rw-r--r--fdisk/sfdisk.examples264
20 files changed, 12771 insertions, 0 deletions
diff --git a/fdisk/Makefile b/fdisk/Makefile
new file mode 100644
index 000000000..e5415acdc
--- /dev/null
+++ b/fdisk/Makefile
@@ -0,0 +1,68 @@
+# Makefile -- Makefile for util-linux Linux utilities
+# Created: Sat Dec 26 20:09:40 1992
+# 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)
+#
+
+include ../MCONFIG
+
+MAN8=
+SBIN=
+
+ifneq "$(CPU)" "sparc"
+# fsck and mkfs will compile, but there is no kernel support on sparc
+ifneq "$(CPU)" "m68k"
+MAN8:=$(MAN8) fdisk.8 cfdisk.8 sfdisk.8
+SBIN:=$(SBIN) fdisk cfdisk sfdisk
+endif
+else
+MAN8:=$(MAN8) fdisk.8
+SBIN:=$(SBIN) fdisk
+endif
+
+all: $(SBIN)
+
+cfdisk.o: cfdisk.c
+ifeq "$(HAVE_SLANG)" "yes"
+ $(CC) -c $(CFLAGS) -DSLCURSES=1 $< -o $@
+else
+ifeq "$(HAVE_NCURSES)" "yes"
+ $(CC) -c $(CFLAGS) $< -o $@
+else
+ :
+endif
+endif
+
+cfdisk: cfdisk.o llseek.o
+ifeq "$(HAVE_SLANG)" "yes"
+ $(CC) $(LDFLAGS) $^ -o $@ $(LIBSLANG)
+else
+ifeq "$(HAVE_NCURSES)" "yes"
+ $(CC) $(LDFLAGS) $^ -o $@ $(LIBCURSES) -lm
+else
+ @echo $@ not made since it requires ncurses or slang
+endif
+endif
+
+# not installed by default
+activate: sfdisk
+ rm -f activate
+ ln -s sfdisk activate
+
+fdisk: fdisk.o llseek.o fdiskbsdlabel.o fdisksgilabel.o fdisksunlabel.o \
+ fdiskaixlabel.o
+fdisk.o: fdisk.c fdisk.h
+fdiskbsdlabel.o: fdiskbsdlabel.c fdisk.h fdiskbsdlabel.h
+fdisksunlabel.o: fdisksunlabel.c fdisksunlabel.h fdisk.h
+fdiskaixlabel.o: fdiskaixlabel.c fdiskaixlabel.h fdisk.h
+sfdisk: sfdisk.o
+
+install: all
+ $(INSTALLDIR) $(SBINDIR)
+ $(INSTALLBIN) $(SBIN) $(SBINDIR)
+ $(INSTALLDIR) $(MAN8DIR)
+ $(INSTALLMAN) $(MAN8) $(MAN8DIR)
+
+.PHONY: clean
+clean:
+ -rm -f *.o *~ core $(SBIN)
diff --git a/fdisk/README.cfdisk b/fdisk/README.cfdisk
new file mode 100644
index 000000000..5241ad136
--- /dev/null
+++ b/fdisk/README.cfdisk
@@ -0,0 +1,45 @@
+Announcing the new curses based fdisk program... 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). I hope that this program will be
+useful to both new and old Linux users, and I hope it will make the
+installation process easier.
+
+
+ **** WARNING ****
+If you write a bad partition table to disk, it may destroy data and
+partitions.
+
+
+You can FTP cfdisk from ftp.cs.unc.edu in the /pub/martin/linux
+directory.
+
+I would also like comments (good and bad) on the user interface, logic
+and ease of use. If you have any suggestions for improvements, I
+would be happy to hear them.
+
+My e-mail address is martin@cs.unc.edu.
+
+-------------------------------------------------------------------
+
+ 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.
+
+___
+Kevin E. Martin University of North Carolina at Chapel Hill
+martin@cs.unc.edu Department of Computer Science
diff --git a/fdisk/README.fdisk b/fdisk/README.fdisk
new file mode 100644
index 000000000..86b182525
--- /dev/null
+++ b/fdisk/README.fdisk
@@ -0,0 +1,583 @@
+`fdisk': the Linux partition table editor
+=========================================
+
+`fdisk' is the Linux partition table editor. In this section we
+examine this utility and try to describe it thoroughly enough so that
+anyone can use it.
+
+* Contents:
+
+* Disks and how they are described.
+* Dividing up your disk.
+* The `fdisk' command.
+* Deleting and adding partitions.
+* Active flags and system types.
+* Extra commands for experts.
+* Warnings for `fdisk' users.
+
+
+Disks and how they are described
+--------------------------------
+
+A typical disk consists physically of one or more circular objects
+called "platters", which rotate about a central axis. Devices called
+"heads" move to specified places on the disk surface to read or write
+information. There is usually one head on each side of every platter,
+and all these heads are attached to a comb-like controller arm which
+moves all of them at the same time, either closer to the centre of the
+disk, or closer to the outer edge.
+
+Suppose the arm is in one position, putting an area of the disk
+surface within reach of one or another of the heads. This total area,
+everything that is accessible without moving the arm, is called a
+"cylinder". (A cylinder is a barrel-shaped cross section of a disk,
+consisting of a circular strip from each side of each platter.) The
+part of a cylinder that one head can read or write without moving is
+called a "track".
+
+Each track is divided into several pie-shaped slices called
+"sectors", which are the smallest parts of the disk which can be read
+or written at a time. The sectors on one disk are usually all the same
+size.
+
+In fact, there are not always two heads to every platter, there are
+some disks which do not have the same amount of data in every cylinder,
+and there may be disks which do not have the same amount of data in
+every sector. These features are usually hidden on PCs by the
+controller card or the BIOS, which map the physical geometry of a disk
+onto a logical geometry, which is what is actually used to access the
+disk.
+
+The numbers which describe the "geometry" of a disk are
+
+ 1. The number of cylinders it contains.
+
+ 2. The number of tracks per cylinder, which is the number of heads.
+
+ 3. The number of sectors per track.
+
+ 4. The number of bytes per sector.
+
+These numbers vary from disk to disk, but a typical PC disk might
+have about 1000 cylinders, half a dozen heads, and 15 or 20 sectors per
+track, with each sector containing 512 bytes or characters; such a disk
+contains 40 to 60 megabytes of data. A "double density" floppy disk
+contains 40 cylinders, with 2 heads (2 tracks per cylinder), and with 9
+sectors per track; such a disk contains 360 kilobytes, or 360 * 1024
+characters. A "high density" 3.5 inch floppy contains 80 cylinders,
+with 2 heads and 18 sectors per track, or 1.44 megabytes, or 1440 *
+1024 characters.
+
+The exact size of a track or cylinder in bytes varies from one disk
+to another. This `fdisk' for Linux deals mainly with cylinders, since
+this is the best unit to use when allocating space for partitions. It
+reports partition sizes in "blocks" of 1024 bytes, or 2 sectors, since
+`mkswap' and the various `mkfs' programs require this number. A block
+is the smallest amount of space which can be set aside for a file in
+the current file systems.
+
+An operating system, such as Linux or DOS or OS/2, may use a disk in
+any way that it wishes, but if two operating systems share the same
+disk, they must agree on who owns what, or else one will interfere with
+the other (that is, by damaging the other's files). A "partition" is a
+section of a hard disk which is handled as a unit by all operating
+systems which can access the disk. The standard way to define
+partitions (for the moment) is the "partition table", a list of
+information which is stored in parts of the disk that don't belong to
+any of the systems using the disk. The beginning of the partition
+table is stored in the disk's primary boot sector, and the rest is
+stored in a chain of sectors scattered throughout the disk.
+
+The first sector on the disk is called the "primary boot block" or
+"primary boot sector" because (1) it comes first, before other, similar
+sectors; (2) it tells where the other, similar sectors are found, so
+that it is logically `prior' to them; and (3) it usually contains code
+which is executed when the system boots up. This sector contains a
+table describing at most four partitions. These areas are called
+"primary partitions".
+
+The partition table in the primary boot sector may also describe at
+most one "extended partition". This is a large area of the disk,
+usually containing all the space which is not in any primary partition.
+Within this space we can set aside other areas which are called
+"logical partitions", because they look almost exactly like primary
+partitions. In fact, the main difference between them is that we can
+boot from primary partitions, while we cannot boot from logical
+partitions. This happens because the address of a primary partition is
+in a fixed place, whereas the address of a secondary partition is not,
+so we require a more complicated process to discover it, one which is
+too difficult for most primary boot programs.
+
+
+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 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
+the new partition, formatting it, for example, under DOS, or running
+`mkfs' under Linux; finally you can copy all the data back. It is
+possible, if you have several partitions, to copy data back and forth
+between them while you change their sizes, but this is a bit risky and
+time consuming. It is better to plan ahead what you will need, since
+it is hard to change it afterwards.
+
+Many people with large disks and recent versions of DOS have their
+entire file system on one large partition. They usually ask, `Isn't
+there any way I can reformat my disk without copying everything off?'
+There is no way to do it using standard DOS utilities, and there is no
+truly safe way to do it using commercial software, because, if you make
+a mistake, you will lose the entire contents of your disk. If you are
+going to back up your disk anyway, you might as well copy the data back
+safely. The Linux FAQ contains references to tools and procedures
+which will allow you to do this, if you dare.
+
+DOS and Linux both allow you to access several partitions on a
+single disk; on DOS these are treated as if they were separate disks or
+drives, and under Linux they are treated as different "devices".
+
+You can have up to 64 partitions on a single IDE disk, or up to 16
+partitions on a single SCSI disk, at least as far as Linux is
+concerned; in practice you will rarely want so many. The maximum size
+of a Linux file system on a single partition depends on the type of
+file system you use. Minix file systems are limited to 64 megabytes.
+You may have all of your Linux files in a single partition, or you may
+have two, three, or more Linux file systems. Similarly you may have
+one or more DOS partitions. If you have several small partitions, you
+run much less risk of losing all your files if your disk gets
+corrupted. On the other hand, you may run out of space on a small
+partition more easily.
+
+Under DOS, you must refer to each partition by a separate drive
+letter, but all partitions are automatically accessible. Under Linux
+only the root partition is automatically accessible, but once we mount
+another partition, it is indistinguishable from the rest of the file
+system. Disks are usually mounted by a command in one of the system
+startup files, `/etc/rc', so you need not worry about having to do it
+yourself whenever you boot the system. But even ordinary users may
+be allowed to mount removable hard disks and floppy disks.
+
+Linux requires at least one partition, which is the `root' of the
+file system. You may prefer to have a separate partition for `/usr',
+which contains most of the executable files, or for `/home', which
+contains most of your private files. You may also wish to set aside a
+partition to use for swap space, depending on the amount of memory your
+PC has. You will certainly need swap space if you have less than 4 Mb
+of RAM and wish to compile anything substantial. You can reserve swap
+space in a file, but you need a partition big enough to hold it, and
+this will probably be less efficient than having a partition devoted to
+swap.
+
+The disk space you need for Linux is discussed in README.prepare.
+
+Are you going to boot Linux from the hard disk, or will you boot
+from a floppy? Some boot programs place severe restrictions on where
+the boot partition can be. LILO is more relaxed about this, but does
+require either the Master Boot Record on your first hard disk, or the
+boot record on one of the first four partitions on your first hard disk.
+
+If you have an extended partition with logical partitions in it, you
+can have only three primary partitions containing data.
+
+
+The `fdisk' command
+-------------------
+
+Every operating system, whether DOS, OS/2, or Linux, should provide
+its own utility for editing hard disk partition tables. At least four
+of these utilities have been called `fdisk', for `Fixed DISK setup
+program', where `fixed' means `not removable'. I believe the first PC
+program named `fdisk' came from Microsoft in about 1985; before that
+time disks were too small to divide into separate sections.
+
+Every operating system has its own peculiarities. Normally you
+should set up a partition for the use of one operating system by using
+its own `fdisk' program. Do not use the Linux `fdisk' to create
+partitions for DOS or for any system other than Linux; otherwise you
+may have problems.
+
+An `fdisk' program performs two functions: it reports how the disk is
+configured, and it changes that configuration by adding or deleting
+partitions. Most `fdisk' programs can also change other information in
+partition tables.
+
+This `fdisk' for Linux operates on one hard disk at a time. If you
+give the command
+
+ fdisk
+
+it reports on, and is able to change, `/dev/hda', the first hard
+disk. (If you have no `/dev/hda', `fdisk' uses `/dev/sda' as the
+default device.) To look at or change the second hard disk, `/dev/hdb',
+give the command
+
+ fdisk /dev/hdb
+
+To look at or change the first SCSI disk, give the command
+
+ fdisk /dev/sda
+
+There are some special forms of the `fdisk' command. One of them,
+suggested by Jim Winstead, simply lists all partitions on all available
+disks:
+
+ fdisk -l (where `l' is a letter, not the digit `1')
+
+The option `-v' is provided to list the current version of the
+`fdisk' command. Finally, there is an option `-s' which is not really
+intended for interactive use. It causes fdisk to print the size of a
+partition in blocks of 1024 bytes as follows:
+
+ fdisk -s /dev/hda7
+ 39934
+
+Because this is intended to be used by `mkfs' and `mkswap' programs,
+it does not return the size of extended partitions or of partitions
+whose system type code is less than 10 (hexadecimal a). If you start
+`fdisk' without using one of these special options, it responds by
+asking for a command:
+
+ Command (m for help): _
+
+Each `fdisk' command consists of a single letter, which must be
+followed by <RETURN> before it is obeyed. Upper and lower case are not
+distinguished. Anything you type after the first character is ignored.
+Give the command `m', and you should see this menu:
+ Command action
+ a toggle a bootable flag
+ d delete a partition
+ l list known partition types
+ m print this menu
+ n add a new partition
+ p print the partition table
+ q quit without saving changes
+ t change a partition's system id
+ u change display/entry units
+ v verify the partition table
+ w write table to disk and exit
+ x extra functionality (experts only)
+
+ Command (m for help): _
+
+The simplest commands are Print, Verify, and Quit. On a small disk, the
+Print command might produce a display like this one:
+
+ Disk /dev/hda: 5 heads, 17 sectors, 977 cylinders
+ Units = cylinders of 85 * 512 bytes
+
+ Device Boot Begin Start End Blocks Id System
+ /dev/hda1 * 1 1 236 10021+ 1 DOS 12-bit FAT
+ /dev/hda2 837 837 977 5992+ 5 Extended
+ /dev/hda3 * 237 237 836 25500 83 Linux native
+ /dev/hda5 837 837 936 4249+ 82 Linux swap
+ /dev/hda6 942 942 977 1522 1 DOS 12-bit FAT
+
+There are 5 partitions reported; `/dev/hda4' does not appear because
+it is not allocated. Partitions 1 and 3 are flagged as bootable. The
+size of each partition is reported in 1 kilobyte blocks; hence the
+primary Linux partition, partition 3, is 25 1/2 megabytes in size. The
+`+' after three of the sizes warns that these partitions contain an odd
+number of sectors: Linux normally allocates filespace in 1 kilobyte
+blocks, so the extra sector in partition 5 is wasted. Id numbers are
+reported in hexadecimal and explained in English.
+
+The display/entry units may be either cylinders or sectors. The
+default is cylinders, but changing the units makes the print command
+display the following table for the system reported above:
+
+ Disk /dev/hda: 5 heads, 17 sectors, 977 cylinders
+ Units = sectors of 1 * 512 bytes
+
+ Device Boot Begin Start End Blocks Id System
+ /dev/hda1 * 1 17 20059 10021+ 1 DOS 12-bit FAT
+ /dev/hda2 71060 71060 83044 5992+ 5 Extended
+ /dev/hda3 * 20060 20060 71059 25500 83 Linux native
+ /dev/hda5 71061 71061 79559 4249+ 82 Linux swap
+ /dev/hda6 79985 80001 83044 1522 1 DOS 12-bit FAT
+
+The start of data in both DOS partitions is 16 sectors after the
+beginning of the partition: this is one reason why you should use DOS's
+own `FDISK' to create DOS partitions. Changing the units to sectors
+also affects the way in which the new partition command asks for the
+beginning and end of a new partition.
+
+*Warning*: it is dangerous to create a new partition when the
+display/entry units are sectors.
+
+The Verify command is useful because
+
+ 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.
+
+The Quit command is also useful. `fdisk' does not actually change
+any data on your disk unless you give a Write command. If you are
+unhappy about any changes you may have made, give the Quit command, and
+your disk will remain as it was before you ran `fdisk'. You can also
+interrupt `fdisk' with `CTRL-C'.
+
+
+Deleting and adding partitions
+------------------------------
+
+Deleting a partition is simple. Give the Delete command by typing
+`d'. `fdisk' asks:
+
+ Partition number (1-6): _
+
+Once you get this far, you must either delete a partition or
+interrupt the program with `CTRL-C' (or whatever your current interrupt
+character is). Note:
+
+ 1. You may delete a nonexistent partition. You will get a warning
+ message.
+
+ 2. You may delete an extended partition. This has the side effect of
+ deleting all partitions greater than or equal to 5.
+
+ 3. You may delete a logical partition. In that case, all partitions
+ above it are renumbered at once. For example, if you delete
+ partition 5, then partition 6 becomes known as partition 5, and
+ partition 7 as partition 6.
+
+Adding a partition is just a bit more complicated. Give the New
+command by typing `n'. `fdisk' allows you to
+
+ 1. Create a primary partition, if there is a free slot in the primary
+ partition table.
+
+ 2. Create an extended partition if there is a free slot in the
+ primary partition table, and if there is no extended partition.
+
+ 3. Create a logical partition if an extended partition exists.
+
+If more than one of these actions is possible, you will be asked to
+select Primary, Extended, or Logical, depending on what is currently
+permissible. Before you create a primary or an extended partition, you
+are asked what slot it is to have in the table (1-4).
+
+You may not add a primary or an extended partition if the selected
+slot in the primary partition table is already occupied: in that case
+you simply return to the main menu. You are not allowed to add a new
+primary partition unless there are sectors available outside the
+extended partition. You are not allowed to add a new logical partition
+unless there are sectors available inside the extended partition.
+
+If space is available, you are prompted for the first cylinder:
+
+ 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. 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]): _
+
+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. 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
+your answer is a size rather than a boundary, and the suffix `m' or `k'
+(upper or lower case) indicates that the size is not given in units of
+sectors or cyliners, but in megabytes or kilobytes respectively. Thus
+possible answers to the last cylinder request above are
+
+700
+ Make cylinder 700 the last cylinder in the partition.
+
++300
+ Make cylinder 237 + 300 = 537 the last cylinder in the partition.
+
++15m
+ Make the partition at least 15 megabytes in size.
+
++12500k
+ 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, 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
+first, just before giving the Write command: this is a safety
+precaution. After giving the Write command, you will see this message:
+
+ The partition table has been altered!
+ Calling ioctl() to re-read partition table.
+ Syncing disks.
+
+If there are no further messages, the kernel has successfully copied
+the information from the partition table into its own internal table.
+But sometimes you will see a message like this one:
+
+ Re-read table failed with error 16: Device or resource busy.
+ Reboot your system to ensure the partition table is updated.
+
+In this case, depending on what you have changed in the partition
+table, it may be dangerous to continue working without rebooting,
+since you may lose or corrupt your data.
+
+
+Here are some important things to note:
+
+ 1. Before you reboot, you *may* run `fdisk' again, either to manage
+ another disk, or to make additional changes to the same disk, or
+ just to check that the changes have been made as you expected.
+ This is true even after you receive the message warning you to
+ reboot.
+
+ 2. It is not a good idea to run any of the programs `mkfs', `mkswap',
+ `mount', or `swapon' if you have received the warning message but
+ have not rebooted. In this case it is dangerous to run any program,
+ but these in particular may cause serious damage to the data on your
+ disk, including the partition tables themselves.
+
+
+Active flags and system types
+-----------------------------
+
+The active flag is a bit in the partition table entry which marks a
+partition as bootable. This is important to some primary boot sector
+programs, which will not boot from an unflagged partition. Other such
+programs do not allow more than one partition to be flagged. Some,
+like LILO, ignore the flags completely. I prefer to flag all bootable
+partitions as active so that they stand out on the menu which `fdisk'
+lists. Fdisk prints a star after the name of a partition's device file
+if its active flag is set.
+
+The Active command changes, or toggles, a partition's active flag.
+Give the Active command, and select a partition by number. If it was
+marked inactive, it will be flagged as active; if it was flagged as
+active, it will be marked inactive. You may set the active flag on an
+extended or logical partition, though the meaning of such a flag is by
+no means clear. This can be used to install LILO as a secondary boot
+loader to boot a Linux which lives on a second hard disk.
+
+The Type command changes the ID number which describes what type a
+partition is. `fdisk' currently recognises 30 system IDs, in the sense
+that it prints a string for each of them, but it allows you to change
+any system ID to any other, with the following exceptions: you may not
+change any partition to or from the type Extended, and you may not
+change a partition whose type is Empty (0) to any other type. You may,
+however, change the type of any data partition to 0, which is
+equivalent to deleting it.
+
+The new system ID or type code is a hexadecimal number. There are
+two ways of listing the numbers which `fdisk' recognises: use the List
+command, which prints the list, or use the Type command, which, when it
+prompts you for the code, says
+
+ Hex code (type L to list codes): _
+
+where the upper case `L' is used for clarity. The codes printed are:
+Some of these numbers are a trifle uncertain. By default `fdisk' uses
+a type of 83. It used to use 81, the type code used by the MINIX
+`fdisk'. It seemed prudent to change the default since (a) many Linux
+`minix' file systems are no longer compatible with MINIX, (b) the ext2
+file system, a native Linux file system, is fairly stable, as is the
+Xia file system, and (c) the number 81 causes problems with DR-DOS.
+Linux does not usually care what values you use for type codes, but
+other systems, in particular DOS, OS/2, and DR-DOS, may.
+
+The value of 82 for Linux swap partitions is my own invention, and
+is intended to give some recognisable distinction to the partitions
+when the values are displayed in hexadecimal.
+
+New active flags and new system type codes are not written to the
+disk until you exit from `fdisk' with the Write command, as described
+above, in the section on deleting and adding partitions.
+
+
+Extra commands for experts
+--------------------------
+
+The eXtra command `x' puts `fdisk' into `expert' mode, in which a
+slightly different set of commands is available. The Active, Delete,
+List, New, Type, Verify, and `eXpert' commands are not available in
+expert mode. The commands Write and Quit are available as in ordinary
+mode, the Print command is available, but produces output in a slightly
+different format, and of course the Menu command prints the expert
+menu. There are several new commands.
+
+ 1. The Return command brings you back to the main menu.
+
+ 2. The Extended command prints the list of table entries which point
+ to other tables. Ordinary users do not need this information.
+ The data is shown as it is stored. The same format is used for
+ the expert Print command.
+
+ 3. The dangerous Begin command allows you to move the start of data
+ in a partition away from its beginning. Other systems create
+ partitions with this format, and it is sometimes useful to be able
+ to reproduce it.
+
+ 4. The slightly dangerous Cylinders command allows you to change the
+ available number of cylinders. For SCSI disk owners, note that we
+ require not the actual number of physical cylinders, but the
+ number of logical cylinders used by DOS and other operating
+ systems.
+
+ 5. The extremely dangerous Heads and Sectors commands allow you to
+ change the number of heads and sectors. It should not be
+ necessary to use these commands unless you have a SCSI disk, whose
+ geometry Linux is not always able to determine. SCSI disk owners
+ note that we need not the actual number of heads or of sectors per
+ track, but the number believed to exist by DOS and other operating
+ systems. *Warning*: If you set either of these numbers to a bad
+ value, you may lose all data on your disk.
+
+Always, after giving any of the commands Begin, Cylinder, Heads, or
+Sectors, you should Return to the main menu and give the Verify command.
+
+
+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 to create partitions
+for Linux.
+
+DR-DOS 5.0 and 6.0 are reported to have difficulties with partition
+ID codes of 80 or more. The Linux `fdisk' used to set the system type
+of new partitions to hexadecimal 81. DR-DOS seems to confuse this with
+hexadecimal 1, a DOS code. The values 82 for swap and 83 for file
+systems should not cause problems with DR-DOS. If they do, you may use
+the `fdisk' command `t' to change the system code of any Linux
+partitions to some number less than hexadecimal 80; I suggest 42 and 43
+for the moment.
+
+Partitioning a hard disk may destroy data which is on that disk if you
+are not careful. Go slowly, write down a description of the partition
+tables before you changed them, and always verify before you write.
+
+Most operating systems and utilities expect that all partitions begin and
+end at cylinder boundaries. This version of `fdisk' does so by default,
+but you can use it to create partitions which begin or end anywhere.
+This does not normally affect Linux, but it is very dangerous, as other
+operating systems (including DOS) may try to `correct' the partition
+boundaries.
+
+It is dangerous to create a new partition when the display/entry
+units are sectors.
+
+The Verify command warns you if anything is wrong. *Always* give a
+Verify command before writing any changes to disk.
+
+If you set the disk geometry (tracks per cylinder, or sectors per
+track) to an incorrect value, you may lose all data on your disk.
+
+Do create BSD/SUN and/or IRIX/SGI disk labels only when you are sure
+that you want them. Both features are intended to allow you READing
+those labels and prevent unintentional formatting of these disks.
diff --git a/fdisk/cfdisk.8 b/fdisk/cfdisk.8
new file mode 100644
index 000000000..c8391af2a
--- /dev/null
+++ b/fdisk/cfdisk.8
@@ -0,0 +1,406 @@
+.\" 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 "3 June 1995" "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. Note:
+
+.B BE EXTREMELY CAREFUL
+if you use the
+.B dd
+command, since a small typo can make all of the data on your disk useless.
+
+For best results, you should always use an OS-specific partition table
+program. For example, you should make DOS partitions with the DOS FDISK
+program and Linux partitions with the Linux 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 "EXIT STATUS"
+0: No errors; 1: Invocation error; 2: I/O error;
+3: cannot get geometry; 4: bad partition table on disk.
+.SH "SEE ALSO"
+fdisk(8)
+.SH BUGS
+The current version does not support multiple disks.
+.SH AUTHOR
+Kevin E. Martin (martin@cs.unc.edu)
diff --git a/fdisk/cfdisk.c b/fdisk/cfdisk.c
new file mode 100644
index 000000000..96ddbbf24
--- /dev/null
+++ b/fdisk/cfdisk.c
@@ -0,0 +1,2642 @@
+/****************************************************************************
+ *
+ * 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
+ * >2GB patches: Sat Feb 11 09:08:10 1995, faith@cs.unc.edu
+ * Prettier menus: Sat Feb 11 09:08:25 1995, Janne Kukonlehto
+ * <jtklehto@stekt.oulu.fi>
+ * Versions 0.8e-n: aeb@cwi.nl
+ * Recognition of NTFS / HPFS difference inspired by patches
+ * from Marty Leisner <leisner@sdsp.mc.xerox.com>
+ * Exit codes by Enrique Zanardi <ezanardi@ull.es>:
+ * 0: all went well
+ * 1: command line error
+ * 2: hardware problems [BAD_SEEK, BAD_READ, BAD_WRITE or BAD_OPEN].
+ * 3: ioctl(fd, HDIO_GETGEO,...) failed [BAD_GEOMETRY].
+ * 4: bad partition table on disk. [BAD_PRIMARY or BAD_LOGICAL].
+ *
+ ****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <fcntl.h>
+#ifdef SLCURSES
+ #include <slcurses.h>
+#else
+#if NCH
+ #include <ncurses.h>
+#else
+ #include <curses.h>
+#endif
+#endif
+#include <signal.h>
+#include <math.h>
+#include <locale.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <linux/hdreg.h>
+#include <linux/fs.h> /* for BLKRRPART */
+
+#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);
+
+#define VERSION "0.8n"
+
+#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_FLAG0 0x55
+#define PART_TABLE_FLAG1 0xAA
+
+#define UNUSABLE -1
+#define FREE_SPACE 0x00
+#define DOS_EXTENDED 0x05
+#define OS2_OR_NTFS 0x07
+#define WIN98_EXTENDED 0x0f
+#define LINUX_EXTENDED 0x85
+#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 READONLY_WARN "Opened disk read-only - you have no permission to write"
+#define WRITE_WARN "Warning!! This may destroy data on your disk!"
+#define YES_NO "Please enter `yes' or `no'"
+#define WRITING_PART "Writing partition table to disk..."
+#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 NOT_DOS_MBR_BOOTABLE "Not precisely one primary partition is bootable. DOS MBR cannot boot this."
+
+#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 is_extended(x) ((x) == DOS_EXTENDED || (x) == WIN98_EXTENDED || \
+ (x) == LINUX_EXTENDED)
+
+#define is_dos_partition(x) ((x) == 1 || (x) == 4 || (x) == 6)
+#define may_have_dos_label(x) (is_dos_partition(x) \
+ || (x) == 7 || (x) == 0xb || (x) == 0xc || (x) == 0xe \
+ || (x) == 0x11 || (x) == 0x14 || (x) == 0x16 || (x) == 0x17)
+
+struct partition {
+ unsigned char boot_ind; /* 0x80 - active */
+ unsigned char head; /* starting head */
+ unsigned char sector; /* starting sector */
+ unsigned char cyl; /* starting cylinder */
+ unsigned char sys_ind; /* What partition type */
+ unsigned char end_head; /* end head */
+ unsigned char end_sector; /* end sector */
+ unsigned char end_cyl; /* end cylinder */
+ unsigned char start4[4]; /* starting sector counting from 0 */
+ unsigned char size4[4]; /* nr of sectors in partition */
+};
+
+/* start_sect and nr_sects are stored little endian on all machines */
+/* moreover, they are not aligned correctly */
+void
+store4_little_endian(unsigned char *cp, unsigned int val) {
+ cp[0] = (val & 0xff);
+ cp[1] = ((val >> 8) & 0xff);
+ cp[2] = ((val >> 16) & 0xff);
+ cp[3] = ((val >> 24) & 0xff);
+}
+
+unsigned int
+read4_little_endian(unsigned char *cp) {
+ return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
+ + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
+}
+
+void
+set_start_sect(struct partition *p, unsigned int start_sect) {
+ store4_little_endian(p->start4, start_sect);
+}
+
+unsigned int
+get_start_sect(struct partition *p) {
+ return read4_little_endian(p->start4);
+}
+
+void
+set_nr_sects(struct partition *p, unsigned int nr_sects) {
+ store4_little_endian(p->size4, nr_sects);
+}
+
+unsigned int
+get_nr_sects(struct partition *p) {
+ return read4_little_endian(p->size4);
+}
+
+#define 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 char magicflag[2];
+ } 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 */
+#define LABELSZ 16
+ char volume_label[LABELSZ+1];
+#define OSTYPESZ 8
+ char ostype[OSTYPESZ+1];
+#define FSTYPESZ 8
+ char fstype[FSTYPESZ+1];
+} partition_info;
+
+char *disk_device = DEFAULT_DEVICE;
+int fd;
+int heads = 0;
+int sectors = 0;
+int cylinders = 0;
+int changed = FALSE;
+int opened = FALSE;
+int opentype;
+int curses_started = 0;
+
+partition_info p_info[MAXIMUM_PARTS];
+partition_info ext_info;
+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 = 28;
+int FSTYPE_START = 38;
+int LABEL_START = 54;
+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",
+ [DOS_EXTENDED]= "Extended",
+ [LINUX_EXTENDED] = "Linux extended",
+ [0x01] = "DOS FAT12",
+ [0x02] = "XENIX root",
+ [0x03] = "XENIX usr",
+ [0x04] = "DOS FAT16",
+ [0x06] = "DOS FAT16 (big)",
+ [OS2_OR_NTFS] = "OS/2 HPFS or NTFS",
+ [0x08] = "AIX",
+ [0x09] = "AIX bootable",
+ [0x0A] = "OS/2 Boot Manager",
+ [0x0B] = "Win95 FAT32",
+ [0x0C] = "Win95 FAT32 (LBA)",
+ [0x0E] = "Win95 FAT16 (LBA)",
+ [0x0F] = "Win95 Extended (LBA)",
+ [0x11] = "Hidden DOS FAT12",
+ [0x14] = "Hidden DOS FAT16",
+ [0x16] = "Hidden DOS FAT16 (big)",
+ [0x17] = "Hidden OS/2 HPFS or NTFS",
+ [0x40] = "Venix 80286",
+ [0x41] = "PPC PReP boot",
+ [0x51] = "Novell?",
+ [0x52] = "Microport",
+ [0x63] = "GNU HURD",
+ [0x64] = "Novell Netware 286",
+ [0x65] = "Novell Netware 386",
+ [0x75] = "PC/IX",
+ [0x80] = "Old MINIX",
+ [0x93] = "Amoeba",
+ [0x94] = "Amoeba BBT",
+ [0xA5] = "BSD/386",
+ [0xA6] = "OpenBSD",
+ [0xA7] = "NEXTSTEP",
+ [0xB7] = "BSDI fs",
+ [0xB8] = "BSDI swap",
+ [0xC7] = "Syrinx",
+ [0xDB] = "CP/M",
+ [0xE1] = "DOS access",
+ [0xE3] = "DOS R/O",
+ [0xEB] = "BeOS fs",
+ [0xF2] = "DOS secondary",
+ [0xFF] = "BBT"
+};
+
+/* Some libc's have their own basename() */
+char *my_basename(char *devname)
+{
+ char *s = rindex(devname, '/');
+ return s ? s+1 : devname;
+}
+
+char *partition_type_text(int i)
+{
+ if (p_info[i].id == UNUSABLE)
+ return "Unusable";
+ else if (p_info[i].id == FREE_SPACE)
+ return "Free Space";
+ else if (p_info[i].id == LINUX) {
+ if (!strcmp(p_info[i].fstype, "ext2"))
+ return "Linux ext2";
+ else
+ return "Linux";
+ } else if (p_info[i].id == OS2_OR_NTFS) {
+ if (!strncmp(p_info[i].fstype, "HPFS", 4))
+ return "OS/2 HPFS";
+ else if (!strncmp(p_info[i].ostype, "OS2", 3))
+ return "OS/2 IFS";
+ else if (!p_info[i].ostype)
+ return p_info[i].ostype;
+ else
+ return "NTFS";
+ } else
+ return partition_type[p_info[i].id];
+}
+
+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 (!curses_started || !warning_last_time)
+ return;
+
+ move(WARNING_START,0);
+ for (i = 0; i < COLS; i++)
+ addch(' ');
+
+ warning_last_time = FALSE;
+}
+
+void print_warning(char *s)
+{
+ if (!curses_started) {
+ fprintf(stderr, "%s\n", s);
+ } else {
+ mvaddstr(WARNING_START, (COLS-strlen(s))/2, s);
+ putchar(BELL); /* CTRL-G */
+
+ warning_last_time = TRUE;
+ }
+}
+
+void die_x(int ret);
+
+void fatal(char *s, int ret)
+{
+ char str[LINE_LENGTH];
+
+ if (curses_started) {
+ sprintf(str, "FATAL ERROR: %s", s);
+ mvaddstr(WARNING_START, (COLS-strlen(str))/2, str);
+ sprintf(str, "Press any key to exit fdisk");
+ mvaddstr(WARNING_START+1, (COLS-strlen(str))/2, str);
+ putchar(BELL); /* CTRL-G */
+ refresh();
+ (void)getch();
+ die_x(ret);
+ } else {
+ fprintf(stderr, "FATAL ERROR: %s\n", s);
+ exit(ret);
+ }
+}
+
+void die(int dummy)
+{
+ die_x(0);
+}
+
+void die_x(int ret)
+{
+ signal(SIGINT, old_SIGINT);
+ signal(SIGTERM, old_SIGTERM);
+#ifdef SLCURSES
+ SLsmg_gotorc(LINES-1, 0);
+ SLsmg_refresh();
+#else
+ mvcur(0, COLS-1, LINES-1, 0);
+#endif
+ nl();
+ endwin();
+ printf("\n");
+ fdexit(ret);
+}
+
+void read_sector(char *buffer, int sect_num)
+{
+ if (ext2_llseek(fd, ((ext2_loff_t) sect_num)*SECTOR_SIZE, SEEK_SET) < 0)
+ fatal(BAD_SEEK, 2);
+ if (read(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE)
+ fatal(BAD_READ, 2);
+}
+
+void write_sector(char *buffer, int sect_num)
+{
+ if (ext2_llseek(fd, ((ext2_loff_t) sect_num)*SECTOR_SIZE, SEEK_SET) < 0)
+ fatal(BAD_SEEK, 2);
+ if (write(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE)
+ fatal(BAD_WRITE, 2);
+}
+
+void dos_copy_to_info(char *to, int tosz, char *from, int fromsz) {
+ int i;
+
+ for(i=0; i<tosz && i<fromsz && isascii(from[i]); i++)
+ to[i] = from[i];
+ to[i] = 0;
+}
+
+void get_dos_label(int i)
+{
+ char sector[128];
+#define DOS_OSTYPE_OFFSET 3
+#define DOS_LABEL_OFFSET 43
+#define DOS_FSTYPE_OFFSET 54
+#define DOS_OSTYPE_SZ 8
+#define DOS_LABEL_SZ 11
+#define DOS_FSTYPE_SZ 8
+ ext2_loff_t offset;
+
+ offset = ((ext2_loff_t) p_info[i].first_sector + p_info[i].offset)
+ * SECTOR_SIZE;
+ if (ext2_llseek(fd, offset, SEEK_SET) == offset
+ && read(fd, &sector, sizeof(sector)) == sizeof(sector)) {
+ dos_copy_to_info(p_info[i].ostype, OSTYPESZ,
+ sector+DOS_OSTYPE_OFFSET, DOS_OSTYPE_SZ);
+ dos_copy_to_info(p_info[i].volume_label, LABELSZ,
+ sector+DOS_LABEL_OFFSET, DOS_LABEL_SZ);
+ dos_copy_to_info(p_info[i].fstype, FSTYPESZ,
+ sector+DOS_FSTYPE_OFFSET, DOS_FSTYPE_SZ);
+ }
+}
+
+void get_ext2_label(int i)
+{
+#define EXT2_SUPER_MAGIC 0xEF53
+#define EXT2LABELSZ 16
+ struct ext2_super_block {
+ char s_dummy0[56];
+ unsigned char s_magic[2];
+ char s_dummy1[62];
+ char s_volume_name[EXT2LABELSZ];
+ char s_last_mounted[64];
+ char s_dummy2[824];
+ } sb;
+ char *label = sb.s_volume_name;
+ ext2_loff_t offset;
+ int j;
+
+ offset = ((ext2_loff_t) p_info[i].first_sector + p_info[i].offset)
+ * SECTOR_SIZE + 1024;
+ if (ext2_llseek(fd, offset, SEEK_SET) == offset
+ && read(fd, &sb, sizeof(sb)) == sizeof(sb)
+ && sb.s_magic[0] + 256*sb.s_magic[1] == EXT2_SUPER_MAGIC) {
+ for(j=0; j<EXT2LABELSZ; j++)
+ if(!isprint(label[j]))
+ label[j] = 0;
+ label[EXT2LABELSZ] = 0;
+ strncpy(p_info[i].volume_label, label, LABELSZ);
+ strncpy(p_info[i].fstype, "ext2", FSTYPESZ);
+ }
+}
+
+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 (is_extended(ext_info.id)) {
+ 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 (is_extended(ext_info.id)) {
+ if (p_info[i].first_sector >= ext_info.first_sector &&
+ p_info[i].last_sector <= ext_info.last_sector) {
+ p_info[i].id = FREE_SPACE;
+ 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 (!is_extended(ext_info.id)) */
+ p_info[i].id = UNUSABLE;
+ } else /* if (p_info[i].id > 0) */
+ while (0); /* Leave these alone */
+ } else { /* if (pri < 4) */
+ 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 (is_extended(ext_info.id)) {
+ if (p_info[i].first_sector >= ext_info.first_sector &&
+ p_info[i].last_sector <= ext_info.last_sector)
+ p_info[i].num = LOGICAL;
+ 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 (!is_extended(ext_info.id)) */
+ p_info[i].num = PRI_OR_LOG;
+ } else /* if (p_info[i].id > 0) */
+ while (0); /* Leave these alone */
+ }
+ }
+}
+
+void remove_part(int i)
+{
+ int p;
+
+ for (p = i; p < num_parts; p++)
+ p_info[p] = p_info[p+1];
+
+ num_parts--;
+}
+
+void insert_empty_part(int i, int first, int last)
+{
+ 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 = 0;
+ p_info[i].flags = 0;
+ p_info[i].id = FREE_SPACE;
+ p_info[i].num = PRI_OR_LOG;
+ p_info[i].volume_label[0] = 0;
+ p_info[i].fstype[0] = 0;
+ p_info[i].ostype[0] = 0;
+
+ 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;
+ ext_info.offset = 0;
+ }
+ if (i == num_parts-1 ||
+ (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num)))
+ ext_info.last_sector = p_info[i].first_sector - 1;
+ 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 want_label)
+{
+ 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; /* bad start or end */
+ }
+
+ for (i = 0; i < num_parts; i++)
+ if (p_info[i].id > 0 && IS_PRIMARY(p_info[i].num))
+ pri++;
+ else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num))
+ log++;
+ if (is_extended(ext_info.id) && log > 0)
+ pri++;
+
+ if (IS_PRIMARY(num)) {
+ if (pri >= 4) {
+ return -1; /* no room for more */
+ } else
+ pri++;
+ }
+
+ for (i = 0; i < num_parts && p_info[i].last_sector < first; i++);
+
+ if (i == num_parts || p_info[i].id != FREE_SPACE
+ || last > p_info[i].last_sector) {
+ return -1;
+ }
+
+ if (is_extended(id)) {
+ if (ext_info.id != FREE_SPACE) {
+ return -1; /* second extended */
+ }
+ else if (IS_PRIMARY(num)) {
+ ext_info.first_sector = first;
+ ext_info.last_sector = last;
+ ext_info.offset = offset;
+ ext_info.flags = flags;
+ ext_info.id = id;
+ ext_info.num = num;
+ ext_info.volume_label[0] = 0;
+ ext_info.fstype[0] = 0;
+ ext_info.ostype[0] = 0;
+ return 0;
+ } else {
+ return -1; /* explicit extended logical */
+ }
+ }
+
+ if (IS_LOGICAL(num)) {
+ if (!is_extended(ext_info.id)) {
+ 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_empty_part(i, p_info[i].first_sector, first-1);
+ i++;
+ }
+
+ if (last != p_info[i].last_sector)
+ insert_empty_part(i+1, last+1, p_info[i].last_sector);
+
+ p_info[i].first_sector = first;
+ p_info[i].last_sector = last;
+ p_info[i].offset = offset;
+ p_info[i].flags = flags;
+ p_info[i].id = id;
+ p_info[i].num = num;
+ p_info[i].volume_label[0] = 0;
+ p_info[i].fstype[0] = 0;
+ p_info[i].ostype[0] = 0;
+ if (want_label) {
+ if (may_have_dos_label(id))
+ get_dos_label(i);
+ else if (id == LINUX)
+ get_ext2_label(i);
+ }
+
+ 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) ||
+ (is_extended(ext_info.id) && 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++;
+}
+
+/* Command menu support by Janne Kukonlehto <jtklehto@phoenix.oulu.fi> September 1994 */
+
+/* Constants for menuType parameter of menuSelect function */
+#define MENU_HORIZ 1
+#define MENU_VERT 2
+#define MENU_ACCEPT_OTHERS 4
+#define MENU_BUTTON 8
+/* Miscellenous constants */
+#define MENU_SPACING 2
+#define MENU_MAX_ITEMS 256 /* for simpleMenu function */
+#define MENU_UP 1
+#define MENU_DOWN 2
+#define MENU_RIGHT 3
+#define MENU_LEFT 4
+
+struct MenuItem
+{
+ int key; /* Keyboard shortcut; if zero, then there is no more items in the menu item table */
+ char *name; /* Item name, should be eight characters with current implementation */
+ char *desc; /* Item description to be printed when item is selected */
+};
+
+/*
+ * Actual function which prints the button bar and highlights the active button
+ * Should not be called directly. Call function menuSelect instead.
+ */
+
+int menuUpdate( int y, int x, struct MenuItem *menuItems, int itemLength,
+ char *available, int menuType, int current )
+{
+ int i, lmargin = x, ymargin = y;
+ /* Print available buttons */
+ move( y, x ); clrtoeol();
+ for( i = 0; menuItems[i].key; i++ )
+ {
+ char buff[20];
+ int lenName;
+ /* Search next available button */
+ while( menuItems[i].key && !strchr(available, menuItems[i].key) )
+ {
+ i++;
+ }
+ if( !menuItems[i].key ) break; /* No more menu items */
+ /* If selected item is not available and we have bypassed it,
+ make current item selected */
+ if( current < i && menuItems[current].key < 0 ) current = i;
+ /* If current item is selected, highlight it */
+ if( current == i ) /*attron( A_REVERSE )*/ standout ();
+ /* Print item */
+ lenName = strlen( menuItems[i].name );
+ if(lenName > itemLength)
+ print_warning("Menu item too long. Menu may look odd.");
+ if( menuType & MENU_BUTTON )
+ sprintf( buff, "[%*s%-*s]", (itemLength - lenName) / 2, "",
+ (itemLength - lenName + 1) / 2 + lenName, menuItems[i].name );
+ else
+ sprintf( buff, "%*s%-*s", (itemLength - lenName) / 2, "",
+ (itemLength - lenName + 1) / 2 + lenName, menuItems[i].name );
+ mvaddstr( y, x, buff );
+ /* Lowlight after selected item */
+ if( current == i ) /*attroff( A_REVERSE )*/ standend ();
+ /* Calculate position for the next item */
+ if( menuType & MENU_VERT )
+ {
+ y += 1;
+ if( y >= WARNING_START )
+ {
+ y = ymargin;
+ x += itemLength + MENU_SPACING;
+ if( menuType & MENU_BUTTON ) x += 2;
+ }
+ }
+ else
+ {
+ x += itemLength + MENU_SPACING;
+ if( menuType & MENU_BUTTON ) x += 2;
+ if( x > COLUMNS - lmargin - 12 )
+ {
+ x = lmargin;
+ y ++ ;
+ }
+ }
+ }
+ /* Print the description of selected item */
+ mvaddstr( WARNING_START + 1,
+ (COLUMNS - strlen( menuItems[current].desc )) / 2,
+ menuItems[current].desc );
+ return y;
+}
+
+/* This function takes a list of menu items, lets the user choose one of them *
+ * and returns the value keyboard shortcut of the selected menu item */
+
+int menuSelect( int y, int x, struct MenuItem *menuItems, int itemLength, char *available, int menuType, int menuDefault )
+{
+ int i, ylast = y, key = 0, current = menuDefault;
+ if( !( menuType & ( MENU_HORIZ | MENU_VERT ) ) )
+ {
+ print_warning("Menu without direction. Defaulting horizontal.");
+ menuType |= MENU_HORIZ;
+ }
+ /* Make sure that the current is one of the available items */
+ while( !strchr(available, menuItems[current].key) )
+ {
+ current ++ ;
+ if( !menuItems[current].key ) current = 0;
+ }
+ /* Repeat until allowable choice has been made */
+ while( !key )
+ {
+ /* Display the menu */
+ ylast = menuUpdate( y, x, menuItems, itemLength, available,
+ menuType, current );
+ refresh();
+ key = getch();
+ /* Clear out all prompts and such */
+ clear_warning();
+ for( i = y; i < ylast; i ++ )
+ {
+ move( i, x );
+ clrtoeol();
+ }
+ move( WARNING_START + 1, 0 );
+ clrtoeol();
+ /* Cursor keys */
+ if( key == ESC )
+ {
+ /* Check whether this is a real ESC or one of extended keys */
+ /*nodelay(stdscr, TRUE);*/
+ key = getch();
+ /*nodelay(stdscr, FALSE);*/
+ if( key == /*ERR*/ ESC )
+ {
+ /* This is a real ESC */
+ key = ESC;
+ }
+ if( key == '[' )
+ {
+ /* This is one extended keys */
+ switch( getch() )
+ {
+ case 'A': /* Up arrow */
+ if( menuType & MENU_VERT )
+ {
+ do {
+ current -- ;
+ if( current < 0 ) while( menuItems[current+1].key ) current ++ ;
+ } while( !strchr( available, menuItems[current].key ) );
+ key = 0;
+ }
+ else
+ key = MENU_UP;
+ break;
+ case 'B': /* Down arrow */
+ if( menuType & MENU_VERT )
+ {
+ do {
+ current ++ ;
+ if( !menuItems[current].key ) current = 0 ;
+ } while( !strchr( available, menuItems[current].key ) );
+ key = 0;
+ }
+ else
+ key = MENU_DOWN;
+ break;
+ case 'C': /* Right arrow */
+ if( menuType & MENU_HORIZ )
+ {
+ do {
+ current ++ ;
+ if( !menuItems[current].key )
+ {
+ current = 0 ;
+ }
+ } while( !strchr( available, menuItems[current].key ) );
+ key = 0;
+ }
+ else
+ key = MENU_RIGHT;
+ break;
+ case 'D': /* Left arrow */
+ if( menuType & MENU_HORIZ )
+ {
+ do {
+ current -- ;
+ if( current < 0 )
+ {
+ while( menuItems[current + 1].key ) current ++ ;
+ }
+ } while( !strchr( available, menuItems[current].key ) );
+ key = 0;
+ }
+ else
+ key = MENU_LEFT;
+ break;
+ }
+ }
+ }
+ /* Enter equals to the keyboard shortcut of current menu item */
+ if( key == 13 )
+ {
+ key = menuItems[current].key;
+ }
+ /* Should all keys to be accepted? */
+ if( key && (menuType & MENU_ACCEPT_OTHERS) ) break;
+ /* Is pressed key among acceptable ones */
+ if( key && (strchr(available, tolower(key)) || strchr(available, key)))
+ break;
+ /* The key has not been accepted so far -> let's reject it */
+ if( key )
+ {
+ key = 0;
+ putchar( BELL );
+ print_warning("Illegal key");
+ }
+ }
+ /* Clear out prompts and such */
+ clear_warning();
+ for( i = y; i <= ylast; i ++ )
+ {
+ move( i, x );
+ clrtoeol();
+ }
+ move( WARNING_START + 1, 0 );
+ clrtoeol();
+ return key;
+}
+
+/* A function which displays "Press a key to continue" *
+ * and waits for a keypress. *
+ * Perhaps calling function menuSelect is a bit overkill but who cares? */
+
+void menuContinue(void)
+{
+ static struct MenuItem menuContinueBtn[]=
+ {
+ { 'c', "", "Press a key to continue" },
+ { 0, NULL, NULL }
+ };
+
+ menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X,
+ menuContinueBtn, 0, "c", MENU_HORIZ | MENU_ACCEPT_OTHERS, 0 );
+}
+
+/* Function menuSelect takes way too many parameters *
+ * Luckily, most of time we can do with this function */
+
+int menuSimple(struct MenuItem *menuItems, int menuDefault)
+{
+ int i, j, itemLength = 0;
+ char available[MENU_MAX_ITEMS];
+ for(i = 0; menuItems[i].key; i++)
+ {
+ j = strlen( menuItems[i].name );
+ if( j > itemLength ) itemLength = j;
+ available[i] = menuItems[i].key;
+ }
+ available[i] = 0;
+ return menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuItems, itemLength,
+ available, MENU_HORIZ | MENU_BUTTON, menuDefault);
+}
+
+/* End of command menu support code */
+
+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) {
+ static struct MenuItem menuPartType[]=
+ {
+ { 'p', "Primary", "Create a new primary partition" },
+ { 'l', "Logical", "Create a new logical partition" },
+ { ESC, "Cancel", "Don't create a partition" },
+ { 0, NULL, NULL }
+ };
+
+ c = menuSimple( menuPartType, 0 );
+ 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;
+
+ move( COMMAND_LINE_Y, COMMAND_LINE_X ); clrtoeol();
+ if (num_sects < p_info[i].last_sector - p_info[i].first_sector + 1) {
+ /* Determine where inside free space to put partition.
+ */
+ static struct MenuItem menuPlace[]=
+ {
+ { 'b', "Beginning", "Add partition at beginning of free space" },
+ { 'e', "End", "Add partition at end of free space" },
+ { ESC, "Cancel", "Don't create a partition" },
+ { 0, NULL, NULL }
+ };
+ c = menuSimple( menuPlace, 0 );
+ 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) && !is_extended(ext_info.id)) {
+ /* 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, DOS_EXTENDED, 0, first, last,
+ (first == 0 ? sectors : 0), 0);
+ first = ext_info.first_sector + ext_info.offset;
+ }
+
+ 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, 0);
+}
+
+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 pn, i, bs, bsz;
+ struct partition *p;
+ 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) {
+ if ((fd = open(disk_device, O_RDONLY)) < 0)
+ fatal(BAD_OPEN, 2);
+ opentype = O_RDONLY;
+ print_warning(READONLY_WARN);
+ if (curses_started) {
+ refresh();
+ getch();
+ clear_warning();
+ }
+ } else
+ opentype = O_RDWR;
+ opened = TRUE;
+
+ /* Blocks are visible in more than one way:
+ e.g. as block on /dev/hda and as block on /dev/hda3
+ By a bug in the Linux buffer cache, we will see the old
+ contents of /dev/hda when the change was made to /dev/hda3.
+ In order to avoid this, discard all blocks on /dev/hda.
+ Note that partition table blocks do not live in /dev/hdaN,
+ so this only plays a role if we want to show volume labels. */
+ ioctl(fd, BLKFLSBUF); /* ignore errors */
+ /* e.g. Permission Denied */
+
+ 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, 3); /* probably a file or cdrom */
+
+ read_sector(buffer.c.b, 0);
+
+ clear_p_info();
+
+ if (!zero_table) {
+ for (i = 0; i < 4; i++) {
+ p = & buffer.p.part[i];
+ bs = get_start_sect(p);
+ bsz = get_nr_sects(p);
+
+ if (p->sys_ind > 0 &&
+ add_part(i, p->sys_ind, p->boot_ind,
+ ((bs <= sectors) ? 0 : bs),
+ bs + bsz - 1,
+ ((bs <= sectors) ? bs : 0),
+ 1)) {
+ fatal(BAD_PRIMARY, 4);
+ }
+ if (is_extended(buffer.p.part[i].sys_ind))
+ tmp_ext = ext_info;
+ }
+
+ if (is_extended(tmp_ext.id)) {
+ ext_info = tmp_ext;
+ logical_sectors[logical] =
+ ext_info.first_sector + ext_info.offset;
+ read_sector(buffer.c.b, logical_sectors[logical++]);
+ i = 4;
+ do {
+ for (pn = 0;
+ pn < 4 && (!buffer.p.part[pn].sys_ind ||
+ is_extended(buffer.p.part[pn].sys_ind));
+ pn++);
+
+ if (pn < 4) {
+ p = & buffer.p.part[pn];
+ bs = get_start_sect(p);
+ bsz = get_nr_sects(p);
+
+ if (add_part(i++, p->sys_ind, p->boot_ind,
+ logical_sectors[logical-1],
+ logical_sectors[logical-1] + bs + bsz - 1,
+ bs, 1))
+ fatal(BAD_LOGICAL, 4);
+ }
+
+ for (pn = 0;
+ pn < 4 && !is_extended(buffer.p.part[pn].sys_ind);
+ pn++);
+ if (pn < 4) {
+ p = & buffer.p.part[pn];
+ bs = get_start_sect(p);
+ logical_sectors[logical] = ext_info.first_sector
+ + ext_info.offset + bs;
+ read_sector(buffer.c.b, logical_sectors[logical++]);
+ }
+ } while (pn < 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))
+ set_start_sect(p,pi->offset);
+ else
+ set_start_sect(p,pi->first_sector + pi->offset);
+ set_nr_sects(p, 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 (is_extended(ext_info.id))
+ fill_part_table(&(buffer->p.part[ext_info.num]), &ext_info);
+
+ buffer->p.magicflag[0] = PART_TABLE_FLAG0;
+ buffer->p.magicflag[1] = PART_TABLE_FLAG1;
+}
+
+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.magicflag[0] != PART_TABLE_FLAG0
+ || buffer->p.magicflag[1] != PART_TABLE_FLAG1)
+ 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 = DOS_EXTENDED;
+ set_start_sect(p, pi->first_sector - ext_info.first_sector - ext_info.offset);
+ set_nr_sects(p, 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.magicflag[0] = PART_TABLE_FLAG0;
+ buffer->p.magicflag[1] = PART_TABLE_FLAG1;
+}
+
+void write_part_table(void)
+{
+ int i, ct, done = FALSE, len;
+ partition_table buffer;
+ struct stat s;
+ int is_bdev;
+ char response[LINE_LENGTH];
+
+ if (opentype == O_RDONLY) {
+ print_warning(READONLY_WARN);
+ refresh();
+ getch();
+ clear_warning();
+ return;
+ }
+
+ is_bdev = 0;
+ if(fstat(fd, &s) == 0 && S_ISBLK(s.st_mode))
+ is_bdev = 1;
+
+ if (is_bdev) {
+ print_warning(WRITE_WARN);
+
+ while (!done) {
+ mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X,
+ "Are you sure you want write the partition table "
+ "to disk? (yes or no): ");
+ len = get_string(response, LINE_LENGTH, NULL);
+ clear_warning();
+ if (len == GS_ESCAPE)
+ return;
+ else if (len == 2 &&
+ toupper(response[0]) == 'N' &&
+ toupper(response[1]) == 'O') {
+ print_warning(NO_WRITE);
+ return;
+ } else if (len == 3 &&
+ toupper(response[0]) == 'Y' &&
+ toupper(response[1]) == 'E' &&
+ toupper(response[2]) == 'S')
+ done = TRUE;
+ else
+ print_warning(YES_NO);
+ }
+
+ clear_warning();
+ print_warning(WRITING_PART);
+ refresh();
+ }
+
+ 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_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);
+ }
+
+ if (is_bdev) {
+ sync();
+ sleep(2);
+ if (!ioctl(fd,BLKRRPART))
+ changed = TRUE;
+ sync();
+ sleep(4);
+
+ clear_warning();
+ if (changed)
+ print_warning(YES_WRITE);
+ else
+ print_warning(RRPART_FAILED);
+ } else
+ print_warning(YES_WRITE);
+
+ /* Check: unique bootable primary partition? */
+ ct = 0;
+ for (i = 0; i < num_parts; i++)
+ if (IS_PRIMARY(i) && p_info[i].flags == ACTIVE_FLAG)
+ ct++;
+ if (ct != 1)
+ print_warning(NOT_DOS_MBR_BOOTABLE);
+}
+
+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) {
+ menuContinue();
+ 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);
+
+ fp_printf(fp, "Sector 0:\n");
+ read_sector(buffer.c.b, 0);
+ fill_primary_table(&buffer);
+ print_file_buffer(fp, buffer.c.b);
+
+ for (i = 0; i < num_parts; i++)
+ if (IS_LOGICAL(p_info[i].num)) {
+ fp_printf(fp, "Sector %d:\n", p_info[i].first_sector);
+ read_sector(buffer.c.b, p_info[i].first_sector);
+ fill_logical_table(&buffer, &(p_info[i]));
+ print_file_buffer(fp, buffer.c.b);
+ }
+
+ if (to_file) {
+ if (!print_only)
+ fclose(fp);
+ } else {
+ menuContinue();
+ }
+}
+
+void print_p_info_entry(FILE *fp, partition_info *p)
+{
+ int size;
+ char part_str[40];
+
+ 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, "%8d%c", p->first_sector,
+ ((p->first_sector/(sectors*heads)) !=
+ ((float)p->first_sector/(sectors*heads)) ?
+ '*' : ' '));
+
+ fp_printf(fp, "%8d%c", p->last_sector,
+ (((p->last_sector+1)/(sectors*heads)) !=
+ ((float)(p->last_sector+1)/(sectors*heads)) ?
+ '*' : ' '));
+
+ fp_printf(fp, "%7d%c", p->offset,
+ ((((p->first_sector == 0 || IS_LOGICAL(p->num)) &&
+ (p->offset != sectors)) ||
+ (p->first_sector != 0 && IS_PRIMARY(p->num) &&
+ p->offset != 0)) ?
+ '#' : ' '));
+
+ size = p->last_sector - p->first_sector + 1;
+ fp_printf(fp, "%8d%c", size,
+ ((size/(sectors*heads)) != ((float)size/(sectors*heads)) ?
+ '*' : ' '));
+
+ fp_printf(fp, " ");
+
+ if (p->id == UNUSABLE)
+ sprintf(part_str, "%.17s", "Unusable");
+ else if (p->id == FREE_SPACE)
+ sprintf(part_str, "%.17s", "Free Space");
+ else if (partition_type[p->id])
+ sprintf(part_str, "%.17s (%02X)", partition_type[p->id], p->id);
+ else
+ sprintf(part_str, "%.17s (%02X)", "Unknown", p->id);
+ fp_printf(fp, "%-22.22s", 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 = is_extended(ext_info.id);
+
+ 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 {
+ menuContinue();
+ }
+}
+
+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 %8d %9d\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 of\n");
+ fp_printf(fp, " # Flags Head Sect Cyl ID Head Sect Cyl Sector Sectors\n");
+ fp_printf(fp, "-- ----- ---- ---- ---- ---- ---- ---- ---- -------- ---------\n");
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0;
+ 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 (is_extended(ext_info.id) && 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 {
+ menuContinue();
+ }
+}
+
+void print_tables(void)
+{
+ int done = FALSE;
+
+ static struct MenuItem menuFormat[]=
+ {
+ { 'r', "Raw", "Print the table using raw data format" },
+ { 's', "Sectors", "Print the table ordered by sectors" },
+ { 't', "Table", "Just print the partition table" },
+ { ESC, "Cancel", "Don't print the table" },
+ { 0, NULL, NULL }
+ };
+
+ while (!done)
+ switch ( toupper(menuSimple( menuFormat, 2)) ) {
+ 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-1998 Kevin E. Martin & aeb",
+ "",
+ "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)) {
+ menuContinue();
+ erase();
+ move(0, 0);
+ cur_line++;
+ } else
+ fp_printf(fp, "%s\n", help_text[cur_line++]);
+
+ menuContinue();
+}
+
+int change_geometry(void)
+{
+ int ret_val = FALSE;
+ int done = FALSE;
+ char def[LINE_LENGTH];
+ char response[LINE_LENGTH];
+ int tmp_val;
+
+ while (!done) {
+ static struct MenuItem menuGeometry[]=
+ {
+ { 'c', "Cylinders", "Change cylinder geometry" },
+ { 'h', "Heads", "Change head geometry" },
+ { 's', "Sectors", "Change sector geometry" },
+ { 'd', "Done", "Done with changing geometry" },
+ { 0, NULL, NULL }
+ };
+ move(COMMAND_LINE_Y, COMMAND_LINE_X);
+ clrtoeol();
+ refresh();
+
+ clear_warning();
+
+ switch (toupper( menuSimple(menuGeometry, 3) )) {
+ 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 'D':
+ done = TRUE;
+ break;
+ default:
+ putchar(BELL);
+ break;
+ }
+ }
+
+ if (ret_val) {
+ int disk_end = heads*sectors*cylinders-1;
+
+ if (p_info[num_parts-1].last_sector > disk_end) {
+ while (p_info[num_parts-1].first_sector > disk_end) {
+ if (p_info[num_parts-1].id == FREE_SPACE ||
+ p_info[num_parts-1].id == UNUSABLE)
+ remove_part(num_parts-1);
+ else
+ del_part(num_parts-1);
+ }
+
+ p_info[num_parts-1].last_sector = disk_end;
+
+ if (ext_info.last_sector > disk_end)
+ ext_info.last_sector = disk_end;
+ } else if (p_info[num_parts-1].last_sector < disk_end) {
+ if (p_info[num_parts-1].id == FREE_SPACE ||
+ p_info[num_parts-1].id == UNUSABLE) {
+ p_info[num_parts-1].last_sector = disk_end;
+ } else {
+ insert_empty_part(num_parts,
+ p_info[num_parts-1].last_sector+1,
+ disk_end);
+ }
+ }
+
+ /* 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 = ((p_info[i].id == LINUX) ? LINUX_SWAP : 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 (is_extended(new_id))
+ 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;
+ char *t;
+
+ 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", my_basename(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"))))));
+
+ t = partition_type_text(i);
+ if (t)
+ mvaddstr(y, FSTYPE_START, t);
+ else
+ mvprintw(y, FSTYPE_START, "Unknown (%02X)", p_info[i].id);
+
+ if (p_info[i].volume_label[0]) {
+ int l = strlen(p_info[i].volume_label);
+ int s = SIZE_START-5-l;
+ mvprintw(y, (s > LABEL_START) ? LABEL_START : s,
+ " [%s] ", p_info[i].volume_label);
+ }
+
+ 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;
+ LABEL_START = (((float)LABEL_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-1, "Part Type");
+ mvaddstr(DISK_TABLE_START, FSTYPE_START, "FS Type");
+ mvaddstr(DISK_TABLE_START, LABEL_START+1, "[Label]");
+ 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 do_curses_fdisk(void)
+{
+ int done = FALSE;
+ char command;
+
+ static struct MenuItem menuMain[]=
+ {
+ { 'b', "Bootable", "Toggle bootable flag of the current partition" },
+ { 'd', "Delete", "Delete the current partition" },
+ { 'g', "Geometry", "Change disk geometry (experts only)" },
+ { 'h', "Help", "Print help screen" },
+ { 'm', "Maximize", "Maximize disk usage of the current partition (experts only)" },
+ { 'n', "New", "Create new partition from free space" },
+ { 'p', "Print", "Print partition table to the screen or to a file" },
+ { 'q', "Quit", "Quit program without writing partition table" },
+ { 't', "Type", "Change the filesystem type (DOS, Linux, OS/2 and so on)" },
+ { 'u', "Units", "Change units of the partition size display (MB, sect, cyl)" },
+ { 'W', "Write", "Write partition table to disk (this might destroy data)" },
+ { 0, NULL, NULL }
+ };
+ curses_started = 1;
+ initscr();
+ init_const();
+
+ old_SIGINT = signal(SIGINT, die);
+ old_SIGTERM = signal(SIGTERM, die);
+#ifdef DEBUG
+ signal(SIGINT, old_SIGINT);
+ signal(SIGTERM, old_SIGTERM);
+#endif
+
+ cbreak();
+ noecho();
+ nonl();
+
+ fill_p_info();
+
+ draw_screen();
+
+ while (!done) {
+ char *s;
+
+ (void)draw_cursor(0);
+
+ if (p_info[cur_part].id == FREE_SPACE) {
+ s = ((opentype == O_RDWR) ? "hnpquW" : "hnpqu");
+ command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8,
+ s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0);
+ } else if (p_info[cur_part].id > 0) {
+ s = ((opentype == O_RDWR) ? "bdhmpqtuW" : "bdhmpqtu");
+ command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8,
+ s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0);
+ } else {
+ s = ((opentype == O_RDWR) ? "hpquW" : "hpqu");
+ command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8,
+ s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0);
+ }
+ switch ( command ) {
+ case 'B':
+ case 'b':
+ 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 MENU_UP : /* Up arrow */
+ if (!draw_cursor(-1))
+ command = 0;
+ else
+ print_warning(NO_MORE_PARTS);
+ break;
+ case MENU_DOWN : /* Down arrow */
+ if (!draw_cursor(1))
+ command = 0;
+ else
+ print_warning(NO_MORE_PARTS);
+ break;
+ case REDRAWKEY:
+ clear();
+ draw_screen();
+ break;
+ default:
+ print_warning(BAD_COMMAND);
+ putchar(BELL); /* CTRL-G */
+ }
+ }
+
+ die_x(0);
+}
+
+void copyright(void)
+{
+ fprintf(stderr, "Copyright (C) 1994-1997 Kevin E. Martin & aeb\n");
+}
+
+void usage(char *prog_name)
+{
+ fprintf(stderr, "\nUsage:\n");
+ fprintf(stderr, "Print version:\n");
+ fprintf(stderr, "\t%s -v\n", prog_name);
+ fprintf(stderr, "Print partition table:\n");
+ fprintf(stderr, "\t%s -P {r|s|t} [options] device\n", prog_name);
+ fprintf(stderr, "Interactive use:\n");
+ fprintf(stderr, "\t%s [options] device\n", prog_name);
+ fprintf(stderr, "
+Options:
+-a: Use arrow instead of highlighting;
+-z: Start with a zero partition table, instead of reading the pt from disk;
+-c C -h H -s S: Override the kernel's idea of the number of cylinders,
+ the number of heads and the number of sectors/track.\n\n");
+
+ copyright();
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ int i, len;
+
+ setlocale(LC_CTYPE, "");
+
+ 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_RDONLY)) < 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();
+
+ return 0;
+}
diff --git a/fdisk/fdisk.8 b/fdisk/fdisk.8
new file mode 100644
index 000000000..6307b98ec
--- /dev/null
+++ b/fdisk/fdisk.8
@@ -0,0 +1,223 @@
+.\" Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu)
+.\" Copyright 1998 Andries E. Brouwer (aeb@cwi.nl)
+.\" May be distributed under the GNU General Public License
+.TH FDISK 8 "11 June 1998" "Linux 2.0" "Linux Programmer's Manual"
+.SH NAME
+fdisk \- Partition table manipulator for Linux
+.SH SYNOPSIS
+.BI "fdisk [\-u] [" device ]
+.sp
+.BI "fdisk \-l [\-u] [" "device ..." ]
+.sp
+.BI "fdisk \-s " "partition ..."
+.sp
+.BI "fdisk \-v
+.SH DESCRIPTION
+Hard disks can be divided into one or more logical disks called
+.IR partitions .
+This division is described in the
+.I "partition table"
+found in sector 0 of the disk.
+
+In the BSD world one talks about `disk slices' and a `disklabel'.
+
+Linux needs at least one partition, namely for its root file system.
+It can use swap files and/or swap partitions, but the latter are more
+efficient. So, usually one will want a second Linux partition
+dedicated as swap partition.
+On Intel compatible hardware, the BIOS that boots the system
+can often only access the first 1024 cylinders of the disk.
+For this reason people with large disks often create a third partition,
+just a few MB large, typically mounted on
+.IR /boot ,
+to store the kernel image and a few auxiliary files needed at boot time,
+so as to make sure that this stuff is accessible to the BIOS.
+There may be reasons of security, ease of administration and backup,
+or testing, to use more than the minimum number of partitions.
+
+.B fdisk
+(in the first form of invocation)
+is a menu driven program for creation and manipulation of
+partition tables.
+It understands DOS type partition tables and BSD or SUN type disklabels.
+
+The
+.I device
+is usually one of the following:
+.br
+.nf
+.RS
+/dev/hda
+/dev/hdb
+/dev/sda
+/dev/sdb
+.RE
+.fi
+(/dev/hd[a-h] for IDE disks, /dev/sd[a-p] for SCSI disks,
+/dev/ed[a-d] for ESDI disks, /dev/xd[ab] for XT disks).
+A device name refers to the entire disk.
+
+The
+.I partition
+is a
+.I device
+name followed by a partition number. For example,
+.B /dev/hda1
+is the first partition on the first IDE hard disk in the system.
+IDE disks can have up to 63 partitions, SCSI disks up to 15.
+See also
+.IR /usr/src/linux/Documentation/devices.txt .
+
+A BSD/SUN type disklabel can describe 8 partitions,
+the third of which should be a `whole disk' partition.
+Do not start a partition that actually uses its first sector
+(like a swap partition) at cylinder 0, since that will
+destroy the disklabel.
+
+An IRIX/SGI type disklabel can describe 16 partitions,
+the eleventh of which should be an entire `volume' partition,
+while the ninth should be labeled `volume header'.
+The volume header will also cover the partition table, i.e.,
+it starts at block zero and extends by default over five cylinders.
+The remaining space in the volume header may be used by header
+directory entries. No partitions may overlap with the volume header.
+Also do not change its type and make some file system on it, since
+you will lose the partition table. Use this type of label only when
+working with Linux on IRIX/SGI machines or IRIX/SGI disks under Linux.
+
+A DOS type partition table can describe an unlimited number
+of partitions. In sector 0 there is room for the description
+of 4 partitions (called `primary'). One of these may be an
+extended partition; this is a box holding logical partitions,
+with descriptors found in a linked list of sectors, each
+preceding the corresponding logical partitions.
+The four primary partitions, present or not, get numbers 1-4.
+Logical partitions start numbering from 5.
+
+In a DOS type partition table the starting offset and the size
+of each partition is stored in two ways: as an absolute number
+of sectors (given in 32 bits) and as a Cylinders/Heads/Sectors
+triple (given in 10+8+6 bits). The former is OK - with 512-byte
+sectors this will work up to 2 TB. The latter has two different
+problems. First of all, these C/H/S fields can be filled only
+when the number of heads and the number of sectors per track
+are known. Secondly, even if we know what these numbers should be,
+the 24 bits that are available do not suffice.
+DOS uses C/H/S only, Windows uses both, Linux never uses C/H/S.
+
+If possible,
+.B fdisk
+will obtain the disk geometry automatically. This is not
+necessarily the physical disk geometry (indeed, modern disks do not
+really have anything like a physical geometry, certainly not something
+that can be described in simplistic Cylinders/Heads/Sectors form),
+but is the disk geometry that MS-DOS uses for the partition table.
+
+Usually all goes well by default, and there are no problems if
+Linux is the only system on the disk. However, if the disk has
+to be shared with other operating systems, it is often a good idea
+to let an fdisk from another operating system make at least one
+partition. When Linux boots it looks at the partition table, and
+tries to deduce what (fake) geometry is required for good
+cooperation with other systems.
+
+Whenever a partition table is printed out, a consistency check is performed
+on the partition table entries. This check verifies that the physical and
+logical start and end points are identical, and that the partition starts
+and ends on a cylinder boundary (except for the first partition).
+
+Some versions of MS-DOS create a first partition which does not begin
+on a cylinder boundary, but on sector 2 of the first cylinder.
+Partitions beginning in cylinder 1 cannot begin on a cylinder boundary, but
+this is unlikely to cause difficulty unless you have OS/2 on your machine.
+
+A sync() and a BLKRRPART ioctl() (reread partition table from disk)
+are performed before exiting when the partition table has been updated.
+Long ago it used to be necessary to reboot after the use of fdisk.
+I do not think this is the case anymore - indeed, rebooting too quickly
+might cause loss of not-yet-written data. Note that both the kernel
+and the disk hardware may buffer data.
+
+.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.
+
+For best results, you should always use an OS-specific partition table
+program. For example, you should make DOS partitions with the DOS FDISK
+program and Linux partitions with the Linux fdisk or Linux cfdisk program.
+
+.SH OPTIONS
+.TP
+.B \-v
+Print version number of
+.B fdisk
+program and exit.
+.TP
+.B \-l
+List the partition tables for
+.BR /dev/hd[a-d] ,
+.BR /dev/sd[a-h] ,
+.BR /dev/ed[a-d] ,
+and then exit.
+.TP
+.B \-u
+When listing partition tables, give sizes in sectors instead
+of cylinders.
+.TP
+.BI "\-s " partition
+The
+.I size
+of the partition (in blocks) is printed on the standard output.
+This value is normally used as an argument to the
+.BR mkfs (8)
+program to specify the size of the partition which will be formatted.
+(Older versions of fdisk would do this only if the partition id is
+greater than 10, in an attempt to refuse DOS partitions;
+this test has been deleted.)
+Note that
+.B "sfdisk -s"
+gives different (namely, correct) answers.
+Reasons for the difference are that the kernel and
+.B fdisk
+need not have the same idea about partition numbering
+(e.g., in case you have BSD slices), and have different
+ideas about the size of an extended partition.
+.SH BUGS
+There are several *fdisk programs around.
+Each has its problems and strengths.
+Try them in the order
+.BR cfdisk ,
+.BR fdisk ,
+.BR sfdisk .
+.PP
+The IRIX/SGI type disklabel is currently not supported by the kernel.
+Moreover, IRIX/SGI header directories are not fully supported yet.
+.PP
+The option `dump partition table to file' is missing.
+.\" .SH AUTHORS
+.\" A. V. Le Blanc (LeBlanc@mcc.ac.uk)
+.\" Bernhard Fastenrath (fasten@informatik.uni-bonn.de)
+.\" Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+.\" Andreas Neuper (ANeuper@GUUG.de)
+.\" and many others.
diff --git a/fdisk/fdisk.c b/fdisk/fdisk.c
new file mode 100644
index 000000000..8cdc6df84
--- /dev/null
+++ b/fdisk/fdisk.c
@@ -0,0 +1,2046 @@
+/* fdisk.c -- Partition table manipulator for Linux.
+ *
+ * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
+ *
+ * This program is free software. You can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation: either version 1 or
+ * (at your option) any later version.
+ *
+ * Before Linux version 0.95c, this program requires a kernel patch.
+ *
+ * Modified, Tue Feb 2 18:46:49 1993, faith@cs.unc.edu to better support SCSI.
+ * Modified, Sat Feb 27 18:11:27 1993, faith@cs.unc.edu: added extfs support.
+ * Modified, Sat Mar 6 10:14:12 1993, faith@cs.unc.edu: added more comments.
+ * Modified, Sat Mar 6 12:25:45 1993, faith@cs.unc.edu:
+ * Added patches from Michael Bischoff (i1041905@ws.rz.tu-bs.de
+ * or mbi@mo.math.nat.tu-bs.de) to fix the following problems:
+ * 1) Incorrect mapping of head/sector/cylinder to absolute sector
+ * 2) Odd sector count causes one sector to be lost
+ * Modified, Sat Mar 6 12:25:52 1993, faith@cs.unc.edu: improved verification.
+ * Modified, Sat Apr 17 15:00:00 1993, LeBlanc@mcc.ac.uk: add -s, fix -l.
+ * Modified, Sat Apr 24 10:00:00 1993, LeBlanc@mcc.ac.uk: fix overlap bug.
+ * Modified, Wed May 5 21:30:00 1993, LeBlanc@mcc.ac.uk: errors to stderr.
+ * Modified, Mon Mar 21 20:00:00 1994, LeBlanc@mcc.ac.uk:
+ * more stderr for messages, avoid division by 0, and
+ * give reboot message only if ioctl(fd, BLKRRPART) fails.
+ * Modified, Mon Apr 25 01:01:05 1994, martin@cs.unc.edu:
+ * 1) Added support for DOS, OS/2, ... compatibility. We should be able
+ * use this fdisk to partition our drives for other operating systems.
+ * 2) Added a print the raw data in the partition table command.
+ * Modified, Wed Jun 22 21:05:30 1994, faith@cs.unc.edu:
+ * Added/changed a few partition type names to conform to cfdisk.
+ * (suggested by Sujal, smpatel@wam.umd.edu)
+ * Modified 3/5/95 leisner@sdsp.mc.xerox.com -- on -l only open
+ * devices RDONLY (instead of RDWR). This allows you to
+ * have the disks as rw-r----- with group disk (and if you
+ * want is safe to setguid fdisk to disk).
+ * Modified Sat Mar 11 10:02 1995 with more partition types, faith@cs.unc.edu
+ * Modified, Thu May 4 01:11:45 1995, esr@snark.thyrsus.com:
+ * It's user-interface cleanup time.
+ * Actual error messages for out-of-bounds values (what a concept!).
+ * Enable read-only access to partition table for learners.
+ * Smart defaults for most numeric prompts.
+ * Fixed a bug preventing a partition from crossing cylinder 8064, aeb, 950801.
+ * Read partition table twice to avoid kernel bug
+ * (from Daniel Quinlan <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.
+ * Fixed for using variable blocksizes (needed by magnet-optical drive-patch)
+ * (from orschaer@cip.informatik.uni-erlangen.de)
+ * Modified, Fri Jul 14 11:13:35 MET DST 1996, jj@sunsite.mff.cuni.cz:
+ * editor for Sun disklabels.
+ * Modified, Wed Jul 3 10:14:17 MET DST 1996, jj@sunsite.mff.cuni.cz:
+ * support for Sun floppies
+ * Modified, Thu Jul 24 16:42:33 MET DST 1997, fasten@shw.com:
+ * LINUX_EXTENDED support
+ * Added Windows 95 partition types, aeb.
+ * Fixed a bug described by johnf@whitsunday.net.au, aeb, 980408.
+ * [There are lots of other bugs - nobody should use this program]
+ * [cfdisk on the other hand is nice and correct]
+ * Try to avoid reading a CD-ROM.
+ * Do not print Begin column -- it confuses too many people -- aeb, 980610.
+ * Modified, Sat Oct 3 14:40:17 MET DST 1998, ANeuper@GUUG.de
+ * Support SGI's partitioning -- an, 980930.
+ * Do the verify using LBA, not CHS, limits -- aeb, 981206.
+ */
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <linux/hdreg.h> /* for HDIO_GETGEO */
+#include <linux/fs.h> /* for BLKRRPART, BLKGETSIZE */
+
+#include "fdisk.h"
+
+#include "fdisksunlabel.h"
+#include "fdisksgilabel.h"
+#include "fdiskaixlabel.h"
+
+#include "../version.h"
+
+#define hex_val(c) ({ \
+ char _c = (c); \
+ isdigit(_c) ? _c - '0' : \
+ tolower(_c) + 10 - 'a'; \
+ })
+
+
+#define DEFAULT_DEVICE "/dev/hda"
+#define ALTERNATE_DEVICE "/dev/sda"
+#define LINE_LENGTH 80
+#define offset(b, n) ((struct partition *)((b) + 0x1be + \
+ (n) * sizeof(struct partition)))
+#define sector(s) ((s) & 0x3f)
+#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
+
+#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
+ ((h) + heads * cylinder(s,c)))
+#define set_hsc(h,s,c,sector) { \
+ s = sector % sectors + 1; \
+ sector /= sectors; \
+ h = sector % heads; \
+ sector /= heads; \
+ c = sector & 0xff; \
+ s |= (sector >> 2) & 0xc0; \
+ }
+
+/* A valid partition table sector ends in 0x55 0xaa */
+unsigned int
+part_table_flag(char *b) {
+ return ((uint) b[510]) + (((uint) b[511]) << 8);
+}
+
+int
+valid_part_table_flag(unsigned char *b) {
+ return (b[510] == 0x55 && b[511] == 0xaa);
+}
+
+void
+write_part_table_flag(char *b) {
+ b[510] = 0x55;
+ b[511] = 0xaa;
+}
+
+/* start_sect and nr_sects are stored little endian on all machines */
+/* moreover, they are not aligned correctly */
+void
+store4_little_endian(unsigned char *cp, unsigned int val) {
+ cp[0] = (val & 0xff);
+ cp[1] = ((val >> 8) & 0xff);
+ cp[2] = ((val >> 16) & 0xff);
+ cp[3] = ((val >> 24) & 0xff);
+}
+
+unsigned int
+read4_little_endian(unsigned char *cp) {
+ return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
+ + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
+}
+
+void
+set_start_sect(struct partition *p, unsigned int start_sect) {
+ store4_little_endian(p->start4, start_sect);
+}
+
+unsigned int
+get_start_sect(struct partition *p) {
+ return read4_little_endian(p->start4);
+}
+
+void
+set_nr_sects(struct partition *p, unsigned int nr_sects) {
+ store4_little_endian(p->size4, nr_sects);
+}
+
+unsigned int
+get_nr_sects(struct partition *p) {
+ return read4_little_endian(p->size4);
+}
+
+/* normally O_RDWR, -l option gives O_RDONLY */
+static int type_open = O_RDWR;
+
+char *disk_device = DEFAULT_DEVICE, /* hda, unless specified */
+ *line_ptr, /* interactive input */
+ line_buffer[LINE_LENGTH],
+ changed[MAXIMUM_PARTS], /* marks changed buffers */
+ buffer[MAX_SECTOR_SIZE], /* first four partitions */
+ *buffers[MAXIMUM_PARTS] /* pointers to buffers */
+ = {buffer, buffer, buffer, buffer};
+
+int fd, /* the disk */
+ ext_index, /* the prime extended partition */
+ listing = 0, /* no aborts for fdisk -l */
+ nowarn = 0, /* no warnings for fdisk -l/-s */
+ dos_compatible_flag = ~0,
+ partitions = 4; /* maximum partition + 1 */
+
+uint heads,
+ sectors,
+ cylinders,
+ sector_size = DEFAULT_SECTOR_SIZE,
+ sector_offset = 1,
+ display_factor = 1, /* in units/sector */
+ unit_flag = 1,
+ extended_offset = 0, /* offset of link pointers */
+ offsets[MAXIMUM_PARTS] = {0, 0, 0, 0};
+
+int sun_label = 0; /* looking at sun disklabel */
+int sgi_label = 0; /* looking at sgi disklabel */
+int aix_label = 0; /* looking at aix disklabel */
+
+struct partition *part_table[MAXIMUM_PARTS] /* partitions */
+ = {offset(buffer, 0), offset(buffer, 1),
+ offset(buffer, 2), offset(buffer, 3)},
+ *ext_pointers[MAXIMUM_PARTS] /* link pointers */
+ = {NULL, NULL, NULL, NULL};
+
+struct systypes sys_types[] = {
+ {0x00, "Empty"},
+ {0x01, "DOS 12-bit FAT"},
+ {0x02, "XENIX root"},
+ {0x03, "XENIX usr"},
+ {0x04, "DOS 16-bit <32M"},
+ {0x05, "Extended"},
+ {0x06, "DOS 16-bit >=32M"},
+ {0x07, "OS/2 HPFS"}, /* or QNX? */
+ {0x08, "AIX"},
+ {0x09, "AIX bootable"},
+ {0x0a, "OS/2 Boot Manager"},
+ {0x0b, "Win95 FAT32"},
+ {0x0c, "Win95 FAT32 (LBA)"},
+ {0x0e, "Win95 FAT16 (LBA)"},
+ {0x0f, "Win95 Extended (LBA)"},
+ {0x11, "Hidden DOS FAT12"},
+ {0x14, "Hidden DOS FAT16"},
+ {0x16, "Hidden DOS FAT16 (big)"},
+ {0x17, "Hidden OS/2 HPFS or NTFS"},
+ {0x40, "Venix 80286"},
+ {0x41, "PPC PReP Boot"},
+ {0x51, "Novell?"},
+ {0x52, "Microport"}, /* or CPM? */
+ {0x63, "GNU HURD"}, /* or System V/386? */
+ {0x64, "Novell Netware 286"},
+ {0x65, "Novell Netware 386"},
+ {0x75, "PC/IX"},
+ {0x80, "Old MINIX"}, /* Minix 1.4a and earlier */
+
+ {LINUX_PARTITION, "Linux/MINIX"}, /* Minix 1.4b and later */
+ {LINUX_SWAP, "Linux swap"},
+ {LINUX_NATIVE, "Linux native"},
+ {LINUX_EXTENDED, "Linux extended"},
+
+ {0x93, "Amoeba"},
+ {0x94, "Amoeba BBT"}, /* (bad block table) */
+ {0xa5, "BSD/386"},
+ {0xa6, "OpenBSD"},
+ {0xa7, "NEXTSTEP"},
+ {0xb7, "BSDI fs"},
+ {0xb8, "BSDI swap"},
+ {0xc7, "Syrinx"},
+ {0xdb, "CP/M"}, /* or Concurrent DOS? */
+ {0xe1, "DOS access"},
+ {0xe3, "DOS R/O"},
+ {0xeb, "BeOS fs"},
+ {0xf2, "DOS secondary"},
+ {0xff, "BBT"}, /* (bad track table) */
+ { 0, NULL }
+};
+
+jmp_buf listingbuf;
+
+void fatal(enum failure why)
+{
+ char error[LINE_LENGTH],
+ *message = error;
+
+ if (listing) {
+ close(fd);
+ longjmp(listingbuf, 1);
+ }
+
+ switch (why) {
+ case usage: message =
+"Usage: fdisk [-b SSZ] [-u] [DISK] Change partition table\n"
+" fdisk -l [-b SSZ] [-u] [DISK] List partition table(s)\n"
+" fdisk -s PARTITION Give partition size(s) in blocks\n"
+" fdisk -v Give fdisk version\n"
+"Here DISK is something like /dev/hdb or /dev/sda\n"
+"and PARTITION is something like /dev/hda7\n"
+"-u: give Start and End in sector (instead of cylinder) units\n"
+"-b 2048: (for certain MO drives) use 2048-byte sectors\n";
+ break;
+ case no_device:
+ message = "A disk block device is needed.\n";
+ break;
+ case no_partition:
+ message = "Given name does not refer to a partition,\n"
+ "or maybe not even to a block device.\n";
+ break;
+ case unable_to_open:
+ sprintf(error, "Unable to open %s\n", disk_device);
+ break;
+ case unable_to_read:
+ sprintf(error, "Unable to read %s\n", disk_device);
+ break;
+ case unable_to_seek:
+ sprintf(error, "Unable to seek on %s\n", disk_device);
+ break;
+ case unable_to_write:
+ sprintf(error, "Unable to write %s\n", disk_device);
+ break;
+ case out_of_memory:
+ message = "Unable to allocate any more memory\n";
+ break;
+ default: message = "Fatal error\n";
+ }
+
+ fputc('\n', stderr);
+ fputs(message, stderr);
+ exit(1);
+}
+
+void menu(void)
+{
+ if (sun_label)
+ puts("Command action\n"
+ " a toggle a read only flag\n" /* sun */
+ " b edit bsd disklabel\n"
+ " c toggle the mountable flag\n" /* sun */
+ " d delete a partition\n"
+ " l list known partition types\n"
+ " m print this menu\n"
+ " n add a new partition\n"
+ " o create a new empty DOS partition table\n"
+ " p print the partition table\n"
+ " q quit without saving changes\n"
+ " s create a new empty Sun disklabel\n" /* sun */
+ " t change a partition's system id\n"
+ " u change display/entry units\n"
+ " v verify the partition table\n"
+ " w write table to disk and exit\n"
+ " x extra functionality (experts only)"
+ );
+ else if(sgi_label)
+ puts("Command action\n"
+ " a select bootable partition\n" /* sgi flavour */
+ " b edit bootfile entry\n" /* sgi */
+ " c select sgi swap partition\n" /* sgi flavour */
+ " d delete a partition\n"
+ " l list known partition types\n"
+ " m print this menu\n"
+ " n add a new partition\n"
+ " o create a new empty DOS partition table\n"
+ " p print the partition table\n"
+ " q quit without saving changes\n"
+ " t change a partition's system id\n"
+ " u change display/entry units\n"
+ " v verify the partition table\n"
+ " w write table to disk and exit\n"
+ );
+ else if(aix_label)
+ puts("Command action\n"
+ " m print this menu\n"
+ " o create a new empty DOS partition table\n"
+ " q quit without saving changes\n"
+ );
+ else
+ puts("Command action\n"
+ " a toggle a bootable flag\n"
+ " b edit bsd disklabel\n"
+ " c toggle the dos compatibility flag\n"
+ " d delete a partition\n"
+ " l list known partition types\n"
+ " m print this menu\n"
+ " n add a new partition\n"
+ " o create a new empty DOS partition table\n"
+ " p print the partition table\n"
+ " q quit without saving changes\n"
+ " t change a partition's system id\n"
+ " u change display/entry units\n"
+ " v verify the partition table\n"
+ " w write table to disk and exit\n"
+ " x extra functionality (experts only)"
+ );
+}
+
+void xmenu(void)
+{
+ if (sun_label)
+ puts("Command action\n"
+ " a change number of alternate cylinders\n" /* sun */
+ " c change number of cylinders\n"
+ " d print the raw data in the partition table\n"
+ " e change number of extra sectors per cylinder\n" /*sun*/
+ " h change number of heads\n"
+ " i change interleave factor\n" /* sun */
+ " o change rotation speed (rpm)\n" /* sun */
+ " m print this menu\n"
+ " p print the partition table\n"
+ " q quit without saving changes\n"
+ " r return to main menu\n"
+ " s change number of sectors\n"
+ " v verify the partition table\n"
+ " w write table to disk and exit\n"
+ " y change number of physical cylinders" /* sun */
+ );
+ else
+ puts("Command action\n"
+ " b move beginning of data in a partition\n" /* !sun */
+ " c change number of cylinders\n"
+ " d print the raw data in the partition table\n"
+ " e list extended partitions\n" /* !sun */
+ " g create an IRIX partition table\n" /* sgi */
+ " h change number of heads\n"
+ " m print this menu\n"
+ " p print the partition table\n"
+ " q quit without saving changes\n"
+ " r return to main menu\n"
+ " s change number of sectors\n"
+ " v verify the partition table\n"
+ " w write table to disk and exit"
+ );
+}
+
+int
+get_sysid(int i) {
+ return (
+ sun_label ? sunlabel->infos[i].id :
+ sgi_label ? sgi_get_sysid(i) : part_table[i]->sys_ind);
+}
+
+struct systypes *
+get_sys_types(void) {
+ return (
+ sun_label ? sun_sys_types :
+ sgi_label ? sgi_sys_types : sys_types);
+}
+
+char *partition_type(unsigned char type)
+{
+ int i;
+ struct systypes *types = get_sys_types();
+
+ for (i=0; types[i].name; i++)
+ if (types[i].index == type)
+ return types[i].name;
+
+ return NULL;
+}
+
+void list_types(struct systypes *sys)
+{
+ uint last[4], done = 0, next = 0, size;
+ int i;
+
+ for (i = 0; sys[i].name; i++);
+ size = i;
+
+ for (i = 3; i >= 0; i--)
+ last[3 - i] = done += (size + i - done) / (i + 1);
+ i = done = 0;
+
+ do {
+ printf("%c%2x %-15.15s", i ? ' ' : '\n',
+ sys[next].index, sys[next].name);
+ next = last[i++] + done;
+ if (i > 3 || next >= last[i]) {
+ i = 0;
+ next = ++done;
+ }
+ } while (done < last[0]);
+ putchar('\n');
+}
+
+void clear_partition(struct partition *p)
+{
+ p->boot_ind = 0;
+ p->head = 0;
+ p->sector = 0;
+ p->cyl = 0;
+ p->sys_ind = 0;
+ p->end_head = 0;
+ p->end_sector = 0;
+ p->end_cyl = 0;
+ set_start_sect(p,0);
+ set_nr_sects(p,0);
+}
+
+void set_partition(int i, struct partition *p, uint start, uint stop,
+ int sysid, uint offset)
+{
+ p->boot_ind = 0;
+ p->sys_ind = sysid;
+ set_start_sect(p, start - offset);
+ set_nr_sects(p, stop - start + 1);
+ if (dos_compatible_flag && (start/(sectors*heads) > 1023))
+ start = heads*sectors*1024 - 1;
+ set_hsc(p->head, p->sector, p->cyl, start);
+ if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
+ stop = heads*sectors*1024 - 1;
+ set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
+ changed[i] = 1;
+}
+
+int test_c(char **m, char *mesg)
+{
+ int val = 0;
+ if (!*m)
+ fprintf(stderr, "You must set");
+ else {
+ fprintf(stderr, " %s", *m);
+ val = 1;
+ }
+ *m = mesg;
+ return val;
+}
+
+int warn_geometry(void)
+{
+ char *m = NULL;
+ int prev = 0;
+ if (!heads)
+ prev = test_c(&m, "heads");
+ if (!sectors)
+ prev = test_c(&m, "sectors");
+ if (!cylinders)
+ prev = test_c(&m, "cylinders");
+ if (!m)
+ return 0;
+ fprintf(stderr,
+ "%s%s.\nYou can do this from the extra functions menu.\n",
+ prev ? " and " : " ", m);
+ return 1;
+}
+
+void update_units(void)
+{
+ int cyl_units = heads * sectors;
+
+ if (unit_flag && cyl_units)
+ display_factor = cyl_units;
+ else
+ display_factor = 1; /* in sectors */
+}
+
+void warn_cylinders(void)
+{
+ if (!sun_label && !sgi_label && cylinders > 1024 && !nowarn)
+ fprintf(stderr, "\n\
+The number of cylinders for this disk is set to %d.\n\
+There is nothing wrong with that, but this is larger than 1024,\n\
+and could in certain setups cause problems with:\n\
+1) software that runs at boot time (e.g., LILO)\n\
+2) booting and partitioning software from other OSs\n\
+ (e.g., DOS FDISK, OS/2 FDISK)\n",
+ cylinders);
+}
+
+void read_extended(struct partition *p)
+{
+ int i;
+ struct partition *q;
+
+ ext_pointers[ext_index] = part_table[ext_index];
+ if (!get_start_sect(p))
+ fprintf(stderr, "Bad offset in primary extended partition\n");
+ else while (IS_EXTENDED (p->sys_ind)) {
+ if (partitions >= MAXIMUM_PARTS) {
+ fprintf(stderr,
+ "Warning: deleting partitions after %d\n",
+ partitions);
+ clear_partition(ext_pointers[partitions - 1]);
+ changed[partitions - 1] = 1;
+ return;
+ }
+ offsets[partitions] = extended_offset + get_start_sect(p);
+ if (!extended_offset)
+ extended_offset = get_start_sect(p);
+ if (ext2_llseek(fd, (ext2_loff_t)offsets[partitions]
+ * sector_size, SEEK_SET) < 0)
+ fatal(unable_to_seek);
+ if (!(buffers[partitions] = (char *) malloc(sector_size)))
+ fatal(out_of_memory);
+ if (sector_size != read(fd, buffers[partitions], sector_size))
+ fatal(unable_to_read);
+ part_table[partitions] = ext_pointers[partitions] = NULL;
+ q = p = offset(buffers[partitions], 0);
+ for (i = 0; i < 4; i++, p++) {
+ if (IS_EXTENDED (p->sys_ind)) {
+ if (ext_pointers[partitions])
+ fprintf(stderr, "Warning: extra link "
+ "pointer in partition table "
+ "%d\n", partitions + 1);
+ else
+ ext_pointers[partitions] = p;
+ } else if (p->sys_ind) {
+ if (part_table[partitions])
+ fprintf(stderr,
+ "Warning: ignoring extra data "
+ "in partition table %d\n",
+ partitions + 1);
+ else
+ part_table[partitions] = p;
+ }
+ }
+ if (!part_table[partitions]) {
+ if (q != ext_pointers[partitions])
+ part_table[partitions] = q;
+ else part_table[partitions] = q + 1;
+ }
+ if (!ext_pointers[partitions]) {
+ if (q != part_table[partitions])
+ ext_pointers[partitions] = q;
+ else ext_pointers[partitions] = q + 1;
+ }
+ p = ext_pointers[partitions++];
+ }
+}
+
+void create_doslabel(void)
+{
+ int i;
+
+ fprintf(stderr,
+ "Building a new DOS disklabel. Changes will remain in memory only,\n"
+ "until you decide to write them. After that, of course, the previous\n"
+ "content won't be recoverable.\n\n");
+
+ sun_nolabel(); /* otherwise always recognised as sun */
+ sgi_nolabel(); /* otherwise always recognised as sgi */
+
+ write_part_table_flag(buffer);
+ for (i = 0; i < 4; i++)
+ clear_partition(part_table[i]);
+ for (i = 1; i < MAXIMUM_PARTS; i++)
+ changed[i] = 0;
+ changed[0] = 1;
+ get_boot(create_empty);
+}
+
+/*
+ * Read MBR. Returns:
+ * -1: no 0xaa55 flag present (possibly entire disk BSD)
+ * 0: found or created label
+ */
+int get_boot(enum action what)
+{
+ int i, sec_fac;
+ struct hd_geometry geometry;
+
+ partitions = 4;
+ sec_fac = sector_size / 512;
+
+ if (what == create_empty)
+ goto got_table; /* skip reading disk */
+
+ if ((fd = open(disk_device, type_open)) < 0) {
+ if ((fd = open(disk_device, O_RDONLY)) < 0)
+ fatal(unable_to_open);
+ else
+ printf("You will not be able to write the partition table.\n");
+ }
+
+ guess_device_type(fd);
+
+ if (sector_size != read(fd, buffer, sector_size))
+ fatal(unable_to_read);
+
+#ifdef HDIO_REQ
+ if (!ioctl(fd, HDIO_REQ, &geometry)) {
+#else
+ if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
+#endif
+ heads = geometry.heads;
+ sectors = geometry.sectors;
+ cylinders = geometry.cylinders;
+ cylinders /= sec_fac; /* do not round up */
+ if (dos_compatible_flag)
+ sector_offset = sectors;
+ } else {
+ if (!ioctl(fd, BLKGETSIZE, &sectors)) {
+ heads = 1;
+ cylinders = 1;
+ sectors /= sec_fac;
+ } else {
+ heads = cylinders = sectors = 0;
+ }
+ }
+ update_units();
+
+got_table:
+
+ if (check_sun_label())
+ return 0;
+
+ if (check_sgi_label())
+ return 0;
+
+ if (check_aix_label())
+ return 0;
+
+ if (!valid_part_table_flag(buffer)) {
+ switch(what) {
+ case fdisk:
+ fprintf(stderr,
+ "Device contains neither a valid DOS partition"
+ " table, nor Sun or SGI disklabel\n");
+#ifdef __sparc__
+ create_sunlabel();
+#else
+ create_doslabel();
+#endif
+ return 0;
+ case require:
+ return -1;
+ case try_only:
+ return -1;
+ case create_empty:
+ break;
+ }
+
+ fprintf(stderr, "Internal error\n");
+ exit(1);
+ }
+
+ warn_cylinders();
+ warn_geometry();
+
+ for (i = 0; i < 4; i++)
+ if(IS_EXTENDED (part_table[i]->sys_ind)) {
+ if (partitions != 4)
+ fprintf(stderr, "Ignoring extra extended "
+ "partition %d\n", i + 1);
+ else read_extended(part_table[ext_index = i]);
+ }
+ for (i = 3; i < partitions; i++)
+ if (!valid_part_table_flag(buffers[i])) {
+ fprintf(stderr,
+ "Warning: invalid flag 0x%04x of partition "
+ "table %d will be corrected by w(rite)\n",
+ part_table_flag(buffers[i]), i + 1);
+ changed[i] = 1;
+ }
+
+ return 0;
+}
+
+/* read line; return 0 or first char */
+int
+read_line(void)
+{
+ line_ptr = line_buffer;
+ if (!fgets(line_buffer, LINE_LENGTH, stdin))
+ return 0;
+ while (*line_ptr && !isgraph(*line_ptr))
+ line_ptr++;
+ return *line_ptr;
+}
+
+char
+read_char(char *mesg)
+{
+ do {
+ fputs(mesg, stdout);
+ } while (!read_line());
+ return *line_ptr;
+}
+
+char
+read_chars(char *mesg)
+{
+ fputs(mesg, stdout);
+ if (!read_line()) {
+ *line_ptr = '\n';
+ line_ptr[1] = 0;
+ }
+ return *line_ptr;
+}
+
+int
+read_hex(struct systypes *sys)
+{
+ int hex;
+
+ while (1)
+ {
+ read_char("Hex code (type L to list codes): ");
+ if (tolower(*line_ptr) == 'l')
+ list_types(sys);
+ else if (isxdigit (*line_ptr))
+ {
+ hex = 0;
+ do
+ hex = hex << 4 | hex_val(*line_ptr++);
+ while (isxdigit(*line_ptr));
+ return hex;
+ }
+ }
+}
+
+/*
+ * Print the message MESG, then read an integer between LOW and HIGH.
+ * If the user hits Enter, DFLT is returned.
+ * Answers like +10 are interpreted as offsets from BASE.
+ *
+ * There is no default if DFLT is not between LOW and HIGH.
+ */
+uint
+read_int(uint low, uint dflt, uint high, uint base, char *mesg)
+{
+ uint i;
+ int default_ok = 1;
+ static char *ms = NULL;
+ static int mslen = 0;
+
+ if (!ms || strlen(mesg)+50 > mslen) {
+ mslen = strlen(mesg)+100;
+ if (!(ms = realloc(ms,mslen)))
+ fatal(out_of_memory);
+ }
+
+ if (dflt < low || dflt > high)
+ default_ok = 0;
+
+ if (default_ok)
+ sprintf(ms, "%s (%d-%d, default %d): ", mesg, low, high, dflt);
+ else
+ sprintf(ms, "%s (%d-%d): ", mesg, low, high);
+
+ while (1) {
+ int use_default = default_ok;
+
+ /* ask question and read answer */
+ while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
+ && *line_ptr != '-' && *line_ptr != '+')
+ continue;
+
+ if (*line_ptr == '+' || *line_ptr == '-') {
+ i = atoi(line_ptr+1);
+ if (*line_ptr == '-')
+ i = -i;
+ while (isdigit(*++line_ptr))
+ use_default = 0;
+ switch (*line_ptr) {
+ case 'c':
+ case 'C':
+ if (!unit_flag)
+ i *= heads * sectors;
+ break;
+ case 'k':
+ case 'K':
+ i *= 2;
+ i /= (sector_size / 512);
+ i /= display_factor;
+ break;
+ case 'm':
+ case 'M':
+ i *= 2048;
+ i /= (sector_size / 512);
+ i /= display_factor;
+ break;
+ case 'g':
+ case 'G':
+ i *= 2048000;
+ i /= (sector_size / 512);
+ i /= display_factor;
+ break;
+ default:
+ break;
+ }
+ i += base;
+ } else {
+ i = atoi(line_ptr);
+ while (isdigit(*line_ptr)) {
+ line_ptr++;
+ use_default = 0;
+ }
+ }
+ if (use_default)
+ printf("Using default value %d\n", i = dflt);
+ if (i >= low && i <= high)
+ break;
+ else
+ printf("Value out of range.\n");
+ }
+ return i;
+}
+
+int get_partition(int warn, int max)
+{
+ int i = read_int(1, 0, max, 0, "Partition number") - 1;
+
+ if (warn && (
+ (!sun_label && !sgi_label && !part_table[i]->sys_ind)
+ || (sun_label &&
+ (!sunlabel->partitions[i].num_sectors ||
+ !sunlabel->infos[i].id))
+ || (sgi_label && (!sgi_get_num_sectors(i)))
+ )) fprintf(stderr, "Warning: partition %d has empty type\n", i+1);
+ return i;
+}
+
+char *const str_units(void)
+{
+ return unit_flag ? "cylinder" : "sector";
+}
+
+void change_units(void)
+{
+ if ((unit_flag = !unit_flag))
+ display_factor = 1;
+ else display_factor = heads * sectors;
+ update_units();
+ printf("Changing display/entry units to %ss\n",
+ str_units());
+}
+
+void toggle_active(int i)
+{
+ struct partition *p = part_table[i];
+
+ if (IS_EXTENDED (p->sys_ind) && !p->boot_ind)
+ fprintf(stderr,
+ "WARNING: Partition %d is an extended partition\n",
+ i + 1);
+ if (p->boot_ind)
+ p->boot_ind = 0;
+ else p->boot_ind = ACTIVE_FLAG;
+ changed[i] = 1;
+}
+
+void toggle_dos(void)
+{
+ dos_compatible_flag = ~dos_compatible_flag;
+ printf("DOS Compatibility flag is ");
+ if (dos_compatible_flag)
+ sector_offset = sectors;
+ else {
+ sector_offset = 1;
+ printf("not ");
+ }
+ printf("set\n");
+}
+
+void delete_partition(int i)
+{
+ struct partition *p = part_table[i], *q = ext_pointers[i];
+
+/* Note that for the fifth partition (i == 4) we don't actually
+ * decrement partitions.
+ */
+
+ if (warn_geometry())
+ return;
+ changed[i] = 1;
+
+ if (sun_label) {
+ sun_delete_partition(i);
+ return;
+ }
+ if (sgi_label) {
+ sgi_delete_partition(i);
+ return;
+ }
+ if (i < 4) {
+ if (IS_EXTENDED (p->sys_ind) && i == ext_index) {
+ while (partitions > 4)
+ free(buffers[--partitions]);
+ ext_pointers[ext_index] = NULL;
+ extended_offset = 0;
+ }
+ clear_partition(p);
+ }
+ else if (!q->sys_ind && i > 4) {
+ free(buffers[--partitions]);
+ clear_partition(ext_pointers[--i]);
+ }
+ else if (i > 3) {
+ if (i > 4) {
+ p = ext_pointers[i - 1];
+ p->boot_ind = 0;
+ p->head = q->head;
+ p->sector = q->sector;
+ p->cyl = q->cyl;
+ p->sys_ind = EXTENDED;
+ p->end_head = q->end_head;
+ p->end_sector = q->end_sector;
+ p->end_cyl = q->end_cyl;
+ set_start_sect(p, get_start_sect(q));
+ set_nr_sects(p, get_nr_sects(q));
+ changed[i - 1] = 1;
+ } else {
+ if(part_table[5]) /* prevent SEGFAULT */
+ set_start_sect(part_table[5],
+ get_start_sect(part_table[5]) +
+ offsets[5] - extended_offset);
+ offsets[5] = extended_offset;
+ changed[5] = 1;
+ }
+ if (partitions > 5) {
+ partitions--;
+ free(buffers[i]);
+ while (i < partitions) {
+ changed[i] = changed[i + 1];
+ buffers[i] = buffers[i + 1];
+ offsets[i] = offsets[i + 1];
+ part_table[i] = part_table[i + 1];
+ ext_pointers[i] = ext_pointers[i + 1];
+ i++;
+ }
+ }
+ else
+ clear_partition(part_table[i]);
+ }
+}
+
+void change_sysid(void)
+{
+ char *temp;
+ int i = get_partition(0, partitions), sys, origsys;
+ struct partition *p = part_table[i];
+
+ origsys = sys = get_sysid(i);
+
+ if (!sys && !sgi_label)
+ printf("Partition %d does not exist yet!\n", i + 1);
+ else while (1) {
+ sys = read_hex (get_sys_types());
+
+ if (!sys && !sgi_label) {
+ printf("Type 0 means free space to many systems\n"
+ "(but not to Linux). Having partitions of\n"
+ "type 0 is probably unwise. You can delete\n"
+ "a partition using the `d' command.\n");
+ /* break; */
+ }
+
+ if (!sun_label && !sgi_label) {
+ if (IS_EXTENDED (sys) != IS_EXTENDED (p->sys_ind)) {
+ printf("You cannot change a partition into"
+ " an extended one or vice versa\n"
+ "Delete it first.\n");
+ break;
+ }
+ }
+
+ if (sys < 256) {
+ if (sun_label && i == 2 && sys != WHOLE_DISK)
+ printf("Consider leaving partition 3 "
+ "as Whole disk (5),\n"
+ "as SunOS/Solaris expects it and "
+ "even Linux likes it.\n\n");
+ if (sgi_label && ((i == 10 && sys != ENTIRE_DISK)
+ || (i == 8 && sys != 0)))
+ printf("Consider leaving partition 9 "
+ "as volume header (0),\nand "
+ "partition 11 as entire volume (6)"
+ "as IRIX expects it.\n\n");
+ if (sys == origsys)
+ break;
+
+ if (sun_label) {
+ sun_change_sysid(i, sys);
+ } else
+ if (sgi_label) {
+ sgi_change_sysid(i, sys);
+ } else
+ part_table[i]->sys_ind = sys;
+ printf ("Changed system type of partition %d "
+ "to %x (%s)\n", i + 1, sys,
+ (temp = partition_type(sys)) ? temp :
+ "Unknown");
+ changed[i] = 1;
+ break;
+ }
+ }
+}
+
+/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
+ * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
+ * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
+ * Lubkin Oct. 1991). */
+
+static void long2chs(ulong ls, uint *c, uint *h, uint *s)
+{
+ int spc = heads * sectors;
+
+ *c = ls / spc;
+ ls = ls % spc;
+ *h = ls / sectors;
+ *s = ls % sectors + 1; /* sectors count from 1 */
+}
+
+static void check_consistency(struct partition *p, int partition)
+{
+ uint pbc, pbh, pbs; /* physical beginning c, h, s */
+ uint pec, peh, pes; /* physical ending c, h, s */
+ uint lbc, lbh, lbs; /* logical beginning c, h, s */
+ uint lec, leh, les; /* logical ending c, h, s */
+
+ if (!heads || !sectors || (partition >= 4))
+ return; /* do not check extended partitions */
+
+/* physical beginning c, h, s */
+ pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
+ pbh = p->head;
+ pbs = p->sector & 0x3f;
+
+/* physical ending c, h, s */
+ pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
+ peh = p->end_head;
+ pes = p->end_sector & 0x3f;
+
+/* compute logical beginning (c, h, s) */
+ long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
+
+/* compute logical ending (c, h, s) */
+ long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
+
+/* Same physical / logical beginning? */
+ if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
+ printf("Partition %d has different physical/logical "
+ "beginnings (non-Linux?):\n", partition + 1);
+ printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs);
+ printf("logical=(%d, %d, %d)\n",lbc, lbh, lbs);
+ }
+
+/* Same physical / logical ending? */
+ if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
+ printf("Partition %d has different physical/logical "
+ "endings:\n", partition + 1);
+ printf(" phys=(%d, %d, %d) ", pec, peh, pes);
+ printf("logical=(%d, %d, %d)\n",lec, leh, les);
+ }
+
+#if 0
+/* Beginning on cylinder boundary? */
+ if (pbh != !pbc || pbs != 1) {
+ printf("Partition %i does not start on cylinder "
+ "boundary:\n", partition + 1);
+ printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs);
+ printf("should be (%d, %d, 1)\n", pbc, !pbc);
+ }
+#endif
+
+/* Ending on cylinder boundary? */
+ if (peh != (heads - 1) || pes != sectors) {
+ printf("Partition %i does not end on cylinder boundary:\n",
+ partition + 1);
+ printf(" phys=(%d, %d, %d) ", pec, peh, pes);
+ printf("should be (%d, %d, %d)\n",
+ pec, heads - 1, sectors);
+ }
+}
+
+void list_disk_geometry(void)
+{
+ printf("\nDisk %s: %d heads, %d sectors, %d cylinders\nUnits = "
+ "%ss of %d * %d bytes\n\n", disk_device, heads, sectors,
+ cylinders, str_units(), display_factor, sector_size);
+}
+
+void list_table(int xtra)
+{
+ struct partition *p;
+ char *type;
+ int digit_last = 0;
+ int i, w;
+
+ if (sun_label) {
+ sun_list_table(xtra);
+ return;
+ }
+
+ if (sgi_label) {
+ sgi_list_table(xtra);
+ return;
+ }
+
+ w = strlen(disk_device);
+ /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
+ but if the device name ends in a digit, say /dev/foo1,
+ then the partition is called /dev/foo1p3. */
+ if (isdigit(disk_device[w-1]))
+ digit_last = 1;
+
+ list_disk_geometry();
+
+ if (w < 5)
+ w = 5;
+ printf("%*s Boot Start End Blocks Id System\n",
+ (digit_last ? w + 2 : w + 1), "Device");
+
+ for (i = 0 ; i < partitions; i++) {
+ if ((p = part_table[i])->sys_ind) {
+ unsigned int psects = get_nr_sects(p);
+ unsigned int pblocks = psects;
+ unsigned int podd = 0;
+
+ if (sector_size < 1024) {
+ pblocks /= (1024 / sector_size);
+ podd = psects % (1024 / sector_size);
+ }
+ if (sector_size > 1024)
+ pblocks *= (sector_size / 1024);
+ printf(
+ "%*s%s%-2d %c %9ld %9ld %9ld%c %2x %s\n",
+/* device */ w, disk_device, (digit_last ? "p" : ""), i+1,
+/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
+ ? '*' : '?',
+/* start */ (long) cround(get_start_sect(p) + offsets[i]),
+/* end */ (long) cround(get_start_sect(p) + offsets[i] + psects
+ - (psects ? 1 : 0)),
+/* odd flag on end */ (long) pblocks, podd ? '+' : ' ',
+/* type id */ p->sys_ind,
+/* type name */ (type = partition_type(p->sys_ind)) ?
+ type : "Unknown");
+ check_consistency(p, i);
+ }
+ }
+}
+
+void x_list_table(int extend)
+{
+ struct partition *p, **q;
+ int i;
+
+ if (extend)
+ q = ext_pointers;
+ else
+ q = part_table;
+ printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n",
+ disk_device, heads, sectors, cylinders);
+ printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
+ for (i = 0 ; i < partitions; i++)
+ if ((p = q[i]) != NULL) {
+ printf("%2d %02x%4d%4d%5d%4d%4d%5d%8d%8d %02x\n",
+ i + 1, p->boot_ind, p->head,
+ sector(p->sector),
+ cylinder(p->sector, p->cyl), p->end_head,
+ sector(p->end_sector),
+ cylinder(p->end_sector, p->end_cyl),
+ get_start_sect(p), get_nr_sects(p), p->sys_ind);
+ if (p->sys_ind)
+ check_consistency(p, i);
+ }
+}
+
+void fill_bounds(uint *first, uint *last)
+{
+ int i;
+ struct partition *p = part_table[0];
+
+ for (i = 0; i < partitions; p = part_table[++i]) {
+ if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) {
+ first[i] = 0xffffffff;
+ last[i] = 0;
+ } else {
+ first[i] = get_start_sect(p) + offsets[i];
+ last[i] = first[i] + get_nr_sects(p) - 1;
+ }
+ }
+}
+
+void check(int n, uint h, uint s, uint c, uint start)
+{
+ uint total, real_s, real_c;
+
+ real_s = sector(s) - 1;
+ real_c = cylinder(s, c);
+ total = (real_c * sectors + real_s) * heads + h;
+ if (!total)
+ fprintf(stderr, "Warning: partition %d contains sector 0\n", n);
+ if (h >= heads)
+ fprintf(stderr,
+ "Partition %d: head %d greater than maximum %d\n",
+ n, h + 1, heads);
+ if (real_s >= sectors)
+ fprintf(stderr, "Partition %d: sector %d greater than "
+ "maximum %d\n", n, s, sectors);
+ if (real_c >= cylinders)
+ fprintf(stderr, "Partitions %d: cylinder %d greater than "
+ "maximum %d\n", n, real_c + 1, cylinders);
+ if (cylinders <= 1024 && start != total)
+ fprintf(stderr,
+ "Partition %d: previous sectors %d disagrees with "
+ "total %d\n", n, start, total);
+}
+
+
+void verify(void)
+{
+ int i, j;
+ uint total = 1;
+ uint first[partitions], last[partitions];
+ struct partition *p = part_table[0];
+
+ if (warn_geometry())
+ return;
+
+ if (sun_label) {
+ verify_sun();
+ return;
+ }
+
+ if (sgi_label) {
+ verify_sgi(1);
+ return;
+ }
+
+ fill_bounds(first, last);
+ for (i = 0; i < partitions; p = part_table[++i])
+ if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) {
+ check_consistency(p, i);
+ if (get_start_sect(p) + offsets[i] < first[i])
+ printf("Warning: bad start-of-data in "
+ "partition %d\n", i + 1);
+ check(i + 1, p->end_head, p->end_sector, p->end_cyl,
+ last[i]);
+ total += last[i] + 1 - first[i];
+ for (j = 0; j < i; j++)
+ if ((first[i] >= first[j] && first[i] <= last[j])
+ || ((last[i] <= last[j] && last[i] >= first[j]))) {
+ printf("Warning: partition %d overlaps "
+ "partition %d.\n", j + 1, i + 1);
+ total += first[i] >= first[j] ?
+ first[i] : first[j];
+ total -= last[i] <= last[j] ?
+ last[i] : last[j];
+ }
+ }
+
+ if (extended_offset) {
+ uint e_last = get_start_sect(part_table[ext_index]) +
+ get_nr_sects(part_table[ext_index]) - 1;
+
+ for (p = part_table[i = 4]; i < partitions;
+ p = part_table[++i]) {
+ total++;
+ if (!p->sys_ind) {
+ if (i != 4 || i + 1 < partitions)
+ printf("Warning: partition %d "
+ "is empty\n", i + 1);
+ }
+ else if (first[i] < extended_offset ||
+ last[i] > e_last)
+ printf("Logical partition %d not entirely in "
+ "partition %d\n", i + 1, ext_index + 1);
+ }
+ }
+
+ if (total > heads * sectors * cylinders)
+ printf("Total allocated sectors %d greater than the maximum "
+ "%d\n", total, heads * sectors * cylinders);
+ else if ((total = heads * sectors * cylinders - total) != 0)
+ printf("%d unallocated sectors\n", total);
+}
+
+void add_partition(int n, int sys)
+{
+ char mesg[48];
+ int i, read = 0;
+ struct partition *p = part_table[n], *q = part_table[ext_index];
+ uint start, stop = 0, limit, temp,
+ first[partitions], last[partitions];
+
+ if (p->sys_ind) {
+ printf("Partition %d is already defined. Delete "
+ "it before re-adding it.\n", n + 1);
+ return;
+ }
+ fill_bounds(first, last);
+ if (n < 4) {
+ start = sector_offset;
+ limit = heads * sectors * cylinders - 1;
+ if (extended_offset) {
+ first[ext_index] = extended_offset;
+ last[ext_index] = get_start_sect(q) +
+ get_nr_sects(q) - 1;
+ }
+ } else {
+ start = extended_offset + sector_offset;
+ limit = get_start_sect(q) + get_nr_sects(q) - 1;
+ }
+ if (unit_flag)
+ for (i = 0; i < partitions; i++)
+ first[i] = (cround(first[i]) - 1) * display_factor;
+
+ sprintf(mesg, "First %s", str_units());
+ do {
+ temp = start;
+ for (i = 0; i < partitions; i++) {
+ int lastplusoff;
+
+ if (start == offsets[i])
+ start += sector_offset;
+ lastplusoff = last[i] + ((n<4) ? 0 : sector_offset);
+ if (start >= first[i] && start <= lastplusoff)
+ start = lastplusoff + 1;
+ }
+ if (start > limit)
+ break;
+ if (start >= temp+display_factor && read) {
+ printf("Sector %d is already allocated\n", temp);
+ temp = start;
+ read = 0;
+ }
+ if (!read && start == temp) {
+ uint i;
+ i = start;
+ start = read_int(cround(i), cround(i), cround(limit),
+ 0, mesg);
+ if (unit_flag) {
+ start = (start - 1) * display_factor;
+ if (start < i) start = i;
+ }
+ read = 1;
+ }
+ } while (start != temp || !read);
+ if (n > 4) /* NOT for fifth partition */
+ offsets[n] = start - sector_offset;
+
+ for (i = 0; i < partitions; i++) {
+ if (start < offsets[i] && limit >= offsets[i])
+ limit = offsets[i] - 1;
+ if (start < first[i] && limit >= first[i])
+ limit = first[i] - 1;
+ }
+ if (start > limit) {
+ printf("No free sectors available\n");
+ if (n > 4) {
+ free(buffers[n]);
+ partitions--;
+ }
+ return;
+ }
+ if (cround(start) == cround(limit))
+ stop = start;
+ else {
+ sprintf(mesg, "Last %s or +size or +sizeM or +sizeK",
+ str_units());
+ stop = read_int(cround(start), cround(limit), cround(limit),
+ cround(start), mesg);
+ if (unit_flag) {
+ stop = stop * display_factor - 1;
+ if (stop >limit)
+ stop = limit;
+ }
+ }
+
+ set_partition(n, p, start, stop, sys, offsets[n]);
+
+ if (IS_EXTENDED (sys)) {
+ ext_index = n;
+ offsets[4] = extended_offset = start;
+ ext_pointers[n] = p;
+ if (!(buffers[4] = calloc(1, sector_size)))
+ fatal(out_of_memory);
+ part_table[4] = offset(buffers[4], 0);
+ ext_pointers[4] = part_table[4] + 1;
+ changed[4] = 1;
+ partitions = 5;
+ }
+ else {
+ if (n > 4)
+ set_partition(n - 1, ext_pointers[n - 1],
+ start - sector_offset, stop, EXTENDED,
+ extended_offset);
+#if 0
+ if ((limit = get_nr_sects(p)) & 1)
+ printf("Warning: partition %d has an odd "
+ "number of sectors.\n", n + 1);
+#endif
+ }
+}
+
+void add_logical(void)
+{
+ if (partitions > 5 || part_table[4]->sys_ind) {
+ if (!(buffers[partitions] = calloc(1, sector_size)))
+ fatal(out_of_memory);
+ part_table[partitions] = offset(buffers[partitions], 0);
+ ext_pointers[partitions] = part_table[partitions] + 1;
+ offsets[partitions] = 0;
+ partitions++;
+ }
+ add_partition(partitions - 1, LINUX_NATIVE);
+}
+
+void new_partition(void)
+{
+ int i, free_primary = 0;
+
+ if (warn_geometry())
+ return;
+
+ if (sun_label) {
+ add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
+ return;
+ }
+
+ if (sgi_label) {
+ sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
+ return;
+ }
+
+ if (partitions >= MAXIMUM_PARTS) {
+ printf("The maximum number of partitions has been created\n");
+ return;
+ }
+
+ for (i = 0; i < 4; i++)
+ free_primary += !part_table[i]->sys_ind;
+ if (!free_primary) {
+ if (extended_offset)
+ add_logical();
+ else
+ printf("You must delete some partition and add "
+ "an extended partition first\n");
+ } else {
+ char c, line[LINE_LENGTH];
+ sprintf(line, "Command action\n %s\n p primary "
+ "partition (1-4)\n", extended_offset ?
+ "l logical (5 or over)" : "e extended");
+ while (1)
+ if ((c = tolower(read_char(line))) == 'p') {
+ add_partition(get_partition(0, 4),
+ LINUX_NATIVE);
+ return;
+ }
+ else if (c == 'l' && extended_offset) {
+ add_logical();
+ return;
+ }
+ else if (c == 'e' && !extended_offset) {
+ add_partition(get_partition(0, 4),
+ EXTENDED);
+ return;
+ }
+ else
+ printf("Invalid partition number "
+ "for type `%c'\n", c);
+
+ }
+}
+
+void write_table(void)
+{
+ int i, error = 0;
+
+ changed[3] = changed[0] || changed[1] || changed[2] || changed[3];
+ if (!sun_label && !sgi_label) {
+ for (i = 3; i < partitions; i++) {
+ if (changed[i]) {
+ write_part_table_flag(buffers[i]);
+ if (ext2_llseek(fd, (ext2_loff_t)offsets[i]
+ * sector_size, SEEK_SET) < 0)
+ fatal(unable_to_seek);
+ if (write(fd, buffers[i], sector_size) != sector_size)
+ fatal(unable_to_write);
+ }
+ }
+ } else if (sgi_label) {
+ /* no test on change? the printf below might be mistaken */
+ sgi_write_table();
+ } else if (sun_label) {
+ if (changed[3] || changed[4] || changed[5] ||
+ changed[6] || changed[7]) {
+ sun_write_table();
+ }
+ }
+
+ printf("The partition table has been altered!\n\n");
+
+ printf("Calling ioctl() to re-read partition table.\n");
+ sync();
+ sleep(2);
+ if ((i = ioctl(fd, BLKRRPART)) != 0) {
+ error = errno;
+ } else {
+ /* some kernel versions (1.2.x) seem to have trouble
+ rereading the partition table, but if asked to do it
+ twice, the second time works. - biro@yggdrasil.com */
+ sync();
+ sleep(2);
+ if((i = ioctl(fd, BLKRRPART)) != 0)
+ error = errno;
+ }
+
+ close(fd);
+
+ printf("Syncing disks.\n");
+ sync();
+ sleep(4); /* for sync() */
+
+ if (i < 0)
+ printf("Re-read table failed with error %d: %s.\nReboot your "
+ "system to ensure the partition table is updated.\n",
+ error, strerror(error));
+
+ if (!sun_label && !sgi_label)
+ printf(
+ "\nWARNING: If you have created or modified any DOS 6.x\n"
+ "partitions, please see the fdisk manual page for additional\n"
+ "information.\n");
+
+ exit(0);
+}
+
+#define MAX_PER_LINE 16
+void print_buffer(char buffer[])
+{
+ int i,
+ l;
+
+ for (i = 0, l = 0; i < sector_size; i++, l++) {
+ if (l == 0)
+ printf("0x%03X:", i);
+ printf(" %02X", (unsigned char) buffer[i]);
+ if (l == MAX_PER_LINE - 1) {
+ printf("\n");
+ l = -1;
+ }
+ }
+ if (l > 0)
+ printf("\n");
+ printf("\n");
+}
+
+void print_raw(void)
+{
+ int i;
+
+ printf("Device: %s\n", disk_device);
+ if (sun_label || sgi_label)
+ print_buffer(buffer);
+ else for (i = 3; i < partitions; i++)
+ print_buffer(buffers[i]);
+}
+
+void move_begin(int i)
+{
+ struct partition *p = part_table[i];
+ uint new, first;
+
+ if (warn_geometry())
+ return;
+ if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED (p->sys_ind)) {
+ printf("Partition %d has no data area\n", i + 1);
+ return;
+ }
+ first = get_start_sect(p) + offsets[i];
+ new = read_int(first, first,
+ get_start_sect(p) + get_nr_sects(p) + offsets[i] - 1,
+ first, "New beginning of data") - offsets[i];
+
+ if (new != get_nr_sects(p)) {
+ first = get_nr_sects(p) + get_start_sect(p) - new;
+ set_nr_sects(p, first);
+ set_start_sect(p, new);
+ changed[i] = 1;
+ }
+}
+
+void xselect(void)
+{
+ while(1) {
+ putchar('\n');
+ switch (tolower(read_char("Expert command (m for help): "))) {
+ case 'a':
+ if (sun_label)
+ sun_set_alt_cyl();
+ break;
+ case 'b':
+ if (!sun_label && !sgi_label)
+ move_begin(get_partition(0, partitions));
+ break;
+ case 'c':
+ cylinders = read_int(1, cylinders, 65535,
+ 0, "Number of cylinders");
+ if (sun_label)
+ sun_set_ncyl(cylinders);
+ warn_cylinders();
+ break;
+ case 'd':
+ print_raw();
+ break;
+ case 'e':
+ if (sgi_label)
+ sgi_set_xcyl();
+ else if (sun_label)
+ sun_set_xcyl();
+ else
+ x_list_table(1);
+ break;
+ case 'g':
+ create_sgilabel();
+ break;
+ case 'h':
+ heads = read_int(1, heads, 256, 0,
+ "Number of heads");
+ update_units();
+ break;
+ case 'i':
+ if (sun_label)
+ sun_set_ilfact();
+ break;
+ case 'o':
+ if (sun_label)
+ sun_set_rspeed();
+ break;
+ case 'p':
+ if (sun_label)
+ list_table(1);
+ else
+ x_list_table(0);
+ break;
+ case 'q':
+ close(fd);
+ exit(0);
+ case 'r':
+ return;
+ case 's':
+ sectors = read_int(1, sectors, 63, 0,
+ "Number of sectors");
+ if (dos_compatible_flag) {
+ sector_offset = sectors;
+ fprintf(stderr, "Warning: setting "
+ "sector offset for DOS "
+ "compatiblity\n");
+ }
+ update_units();
+ break;
+ case 'v':
+ verify();
+ break;
+ case 'w':
+ write_table(); /* does not return */
+ break;
+ case 'y':
+ if (sun_label)
+ sun_set_pcylcount();
+ break;
+ default:
+ xmenu();
+ }
+ }
+}
+
+int
+is_ide_cdrom(char *device) {
+ /* No device was given explicitly, and we are trying some
+ likely things. But opening /dev/hdc may produce errors like
+ "hdc: tray open or drive not ready"
+ if it happens to be a CD-ROM drive. It even happens that
+ the process hangs on the attempt to read a music CD.
+ So try to be careful. This only works since 2.1.73. */
+
+ FILE *procf;
+ char buf[100];
+ struct stat statbuf;
+
+ if (strncmp("/dev/hd", device, 7))
+ return 0;
+ sprintf(buf, "/proc/ide/%s/media", device+5);
+ procf = fopen(buf, "r");
+ if (procf != NULL && fgets(buf, sizeof(buf), procf))
+ return !strncmp(buf, "cdrom", 5);
+
+ /* Now when this proc file does not exist, skip the
+ device when it is read-only. */
+ if (stat(device, &statbuf) == 0)
+ return (statbuf.st_mode & 0222) == 0;
+
+ return 0;
+}
+
+void try(char *device, int user_specified)
+{
+ disk_device = device;
+ if (!setjmp(listingbuf)) {
+ if (!user_specified)
+ if (is_ide_cdrom(device))
+ return;
+ if ((fd = open(disk_device, type_open)) >= 0) {
+ if (get_boot(try_only) < 0) {
+ list_disk_geometry();
+ if (btrydev(device) < 0)
+ fprintf(stderr,
+ "Disk %s doesn't contain a valid "
+ "partition table\n", device);
+ close(fd);
+ } else {
+ close(fd);
+ list_table(0);
+ if (!sun_label && partitions > 4)
+ delete_partition(ext_index);
+ }
+ } else {
+ /* Ignore other errors, since we try IDE
+ and SCSI hard disks which may not be
+ installed on the system. */
+ if(errno == EACCES) {
+ fprintf(stderr, "Cannot open %s\n", device);
+ return;
+ }
+ }
+ }
+}
+
+void
+dummy(int *kk) {}
+
+int
+main(int argc, char **argv)
+{
+ int i, j, s, c;
+ int optl = 0, opts = 0;
+ char *part;
+
+
+ /*
+ * Calls:
+ * fdisk -v
+ * fdisk -l [-b sectorsize] [-u] [device] ...
+ * fdisk -s [partition] ...
+ * fdisk [-b sectorsize] [-u] [device]
+ */
+ while ((c = getopt(argc, argv, "b:lsuv")) != EOF) {
+ switch (c) {
+ case 'b':
+ sector_size = atoi(optarg);
+ if (sector_size != 512 && sector_size != 1024 &&
+ sector_size != 2048)
+ fatal(usage);
+ sector_offset = 2;
+ break;
+ case 'l':
+ optl = 1;
+ break;
+ case 's':
+ opts = 1;
+ break;
+ case 'u':
+ unit_flag = 0;
+ break;
+ case 'v':
+ printf("fdisk v" UTIL_LINUX_VERSION "\n");
+ exit(0);
+ default:
+ fatal(usage);
+ }
+ }
+
+ if (optl) {
+ listing = 1;
+ nowarn = 1;
+ type_open = O_RDONLY;
+ if (argc > optind) {
+ int k;
+ /* avoid gcc warning:
+ variable `k' might be clobbered by `longjmp' */
+ dummy(&k);
+ for(k=optind; k<argc; k++)
+ try(argv[k], 1);
+ } else {
+ try("/dev/hda", 0);
+ try("/dev/hdb", 0);
+ try("/dev/hdc", 0); /* often a CDROM */
+ try("/dev/hdd", 0);
+ try("/dev/sda", 0);
+ try("/dev/sdb", 0);
+ try("/dev/sdc", 0);
+ try("/dev/sdd", 0);
+ try("/dev/sde", 0);
+ try("/dev/sdf", 0);
+ try("/dev/sdg", 0);
+ try("/dev/sdh", 0);
+ try("/dev/eda", 0); /* PS/2 ESDI drives */
+ try("/dev/edb", 0);
+ try("/dev/edc", 0);
+ try("/dev/edd", 0);
+ try("/dev/rd/c0d0", 0); /* DAC960 RAID disks */
+ try("/dev/rd/c0d1", 0);
+ try("/dev/rd/c0d2", 0);
+ try("/dev/rd/c0d3", 0);
+ try("/dev/rd/c0d4", 0);
+ try("/dev/rd/c0d5", 0);
+ try("/dev/rd/c0d6", 0);
+ try("/dev/rd/c0d7", 0);
+ }
+ exit(0);
+ }
+
+ if (opts) {
+ /* Very silly assumptions here about device naming */
+ /* All this junk will disappear again */
+ nowarn = 1;
+ disk_device = (char *) malloc(16);
+ type_open = O_RDONLY;
+
+ opts = argc - optind;
+ if (opts <= 0)
+ fatal(usage);
+
+ for (j = optind; j < argc; j++) {
+ part = argv[j];
+ if (strncmp(part, "/dev/rd/", 8) == 0) {
+ char *p = strrchr(part, 'p');
+ if (p == NULL)
+ fatal(usage);
+ if (!(i = atoi(p + 1)))
+ fatal(usage);
+ i--; /* count from 0 */
+ *p = '\0';
+ strcpy(disk_device, part);
+ } else {
+ if (strlen(part) < 9)
+ fatal(usage);
+ if (!(i = atoi(part + 8)))
+ fatal(usage);
+ i--; /* count from 0 */
+ strncpy(disk_device, part, 8);
+ disk_device[8] = 0;
+ }
+ if ((fd = open(disk_device, type_open)) < 0)
+ fatal(unable_to_open);
+ close(fd);
+ if (get_boot(require) < 0)
+ exit(1);
+ if (i >= partitions)
+ exit(1);
+#if defined(sparc)
+ if (!sun_label) {
+ int id = sunlabel->infos[i].id;
+
+ if (!(id > 1 && id != WHOLE_DISK))
+ exit(1);
+ s = get_num_sectors(sunlabel->partitions[i]);
+ } else
+#endif
+ s = get_nr_sects(part_table[i]);
+ if (opts == 1)
+ printf("%d\n", s/2);
+ else
+ printf("%s: %d\n", argv[j], s/2);
+ }
+ exit(0);
+ }
+
+ if (argc-optind == 1)
+ disk_device = argv[optind];
+ else if (argc-optind != 0)
+ fatal(usage);
+ else {
+ if ((fd = open(DEFAULT_DEVICE, O_RDWR)) < 0)
+ disk_device = ALTERNATE_DEVICE;
+ else close(fd);
+ printf("Using %s as default device!\n", disk_device);
+ }
+ get_boot(fdisk);
+
+ while (1) {
+ putchar('\n');
+ switch (tolower(read_char("Command (m for help): "))) {
+ case 'a':
+ if (sun_label)
+ toggle_sunflags(get_partition(1, partitions),
+ 0x01);
+ else
+ if (sgi_label)
+ sgi_set_bootpartition(
+ get_partition(1, partitions));
+ else
+ toggle_active(get_partition(1, partitions));
+ break;
+ case 'b':
+ if (sgi_label) {
+ printf("\nThe current boot file is: %s\n",
+ sgi_get_bootfile());
+ if (read_chars("Please enter the name of the "
+ "new boot file: ") == '\n')
+ printf("Boot file unchanged\n");
+ else
+ sgi_set_bootfile(line_ptr);
+ } else
+ bselect();
+ break;
+ case 'c':
+ if (sun_label)
+ toggle_sunflags(get_partition(1, partitions),
+ 0x10);
+ else
+ if (sgi_label)
+ sgi_set_swappartition(
+ get_partition(1, partitions));
+ else
+ toggle_dos();
+ break;
+ case 'd':
+ delete_partition(
+ get_partition(1, partitions));
+ break;
+ case 'i':
+ if (sgi_label)
+ create_sgiinfo();
+ else
+ menu();
+ case 'l':
+ list_types(get_sys_types());
+ break;
+ case 'n':
+ new_partition();
+ break;
+ case 'o':
+ create_doslabel();
+ break;
+ case 'p':
+ list_table(0);
+ break;
+ case 'q':
+ close(fd);
+ exit(0);
+ case 's':
+ create_sunlabel();
+ break;
+ case 't':
+ change_sysid();
+ break;
+ case 'u':
+ change_units();
+ break;
+ case 'v':
+ verify();
+ break;
+ case 'w':
+ write_table(); /* does not return */
+ break;
+ case 'x':
+ if( sgi_label ) {
+ fprintf(stderr,
+ "\n\tSorry, no experts menu for SGI "
+ "partition tables available.\n\n");
+ } else
+ xselect();
+ break;
+ default: menu();
+ }
+ }
+ return 0;
+}
diff --git a/fdisk/fdisk.h b/fdisk/fdisk.h
new file mode 100644
index 000000000..080515e5f
--- /dev/null
+++ b/fdisk/fdisk.h
@@ -0,0 +1,85 @@
+/*
+ fdisk.h
+*/
+
+#define DEFAULT_SECTOR_SIZE 512
+#define MAX_SECTOR_SIZE 2048
+#define SECTOR_SIZE 512 /* still used in BSD code */
+#define MAXIMUM_PARTS 60
+
+#define ACTIVE_FLAG 0x80
+
+#define EXTENDED 0x05
+#define WIN98_EXTENDED 0x0f
+#define LINUX_PARTITION 0x81
+#define LINUX_SWAP 0x82
+#define LINUX_NATIVE 0x83
+#define LINUX_EXTENDED 0x85
+
+#define IS_EXTENDED(i) \
+ ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
+
+#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
+
+#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);
+
+struct partition {
+ unsigned char boot_ind; /* 0x80 - active */
+ unsigned char head; /* starting head */
+ unsigned char sector; /* starting sector */
+ unsigned char cyl; /* starting cylinder */
+ unsigned char sys_ind; /* What partition type */
+ unsigned char end_head; /* end head */
+ unsigned char end_sector; /* end sector */
+ unsigned char end_cyl; /* end cylinder */
+ unsigned char start4[4]; /* starting sector counting from 0 */
+ unsigned char size4[4]; /* nr of sectors in partition */
+};
+
+enum failure {usage, unable_to_open, unable_to_read, unable_to_seek,
+ unable_to_write, out_of_memory, no_partition, no_device};
+
+enum action {fdisk, require, try_only, create_empty};
+
+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_boot(enum action what);
+extern int get_partition(int warn, int max);
+extern void list_types(struct systypes *sys);
+extern int read_line (void);
+extern char read_char(char *mesg);
+extern int read_hex(struct systypes *sys);
+uint read_int(uint low, uint dflt, uint high, uint base, char *mesg);
+extern char *const str_units(void);
+
+extern unsigned int get_start_sect(struct partition *p);
+extern unsigned int get_nr_sects(struct partition *p);
+
+/* prototypes for fdiskbsdlabel.c */
+extern void bselect(void);
+extern int btrydev (char * dev);
+
+/* prototypes for fdisksgilabel.c */
+extern int valid_part_table_flag(unsigned char *b);
diff --git a/fdisk/fdiskaixlabel.c b/fdisk/fdiskaixlabel.c
new file mode 100644
index 000000000..848a6ece8
--- /dev/null
+++ b/fdisk/fdiskaixlabel.c
@@ -0,0 +1,64 @@
+#include <stdio.h> /* stderr */
+#include <stdlib.h> /* uint */
+#include <string.h> /* strstr */
+#include <unistd.h> /* write */
+
+#include <endian.h>
+
+#include "fdisk.h"
+#include "fdiskaixlabel.h"
+
+static int other_endian = 0;
+static short volumes=1;
+
+/*
+ * only dealing with free blocks here
+ */
+
+void
+aix_info( void )
+{
+ printf(
+ "\n\tThere is a valid AIX label on this disk.\n"
+ "\tUnfortunately Linux cannot handle these\n"
+ "\tdisks at the moment. Nevertheless some\n"
+ "\tadvice:\n"
+ "\t1. fdisk will destroy its contents on write.\n"
+ "\t2. Be sure that this disk is NOT a still vital\n"
+ "\t part of a volume group. (Otherwise you may\n"
+ "\t erase the other disks as well, if unmirrored.)\n"
+ "\t3. Before deleting this physical volume be sure\n"
+ "\t to remove the disk logically from your AIX\n"
+ "\t machine. (Otherwise you become an AIXpert).\n"
+ );
+}
+
+void
+aix_nolabel( void )
+{
+ aixlabel->magic = 0;
+ aix_label = 0;
+ partitions = 4;
+ memset( buffer, 0, sizeof(buffer) ); /* avoid fdisk cores */
+ return;
+}
+
+int
+check_aix_label( void )
+{
+ if (aixlabel->magic != AIX_LABEL_MAGIC &&
+ aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
+ aix_label = 0;
+ other_endian = 0;
+ return 0;
+ }
+ other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
+ update_units();
+ aix_label = 1;
+ partitions= 1016;
+ volumes = 15;
+ aix_info();
+ aix_nolabel(); /* %% */
+ aix_label = 1; /* %% */
+ return 1;
+}
diff --git a/fdisk/fdiskaixlabel.h b/fdisk/fdiskaixlabel.h
new file mode 100644
index 000000000..fd95bc015
--- /dev/null
+++ b/fdisk/fdiskaixlabel.h
@@ -0,0 +1,34 @@
+#include <linux/types.h> /* for __u32 etc */
+/*
+ * Copyright (C) Andreas Neuper, Sep 1998.
+ * This file may be redistributed under
+ * the terms of the GNU Public License.
+ */
+
+typedef struct {
+ unsigned int magic; /* expect AIX_LABEL_MAGIC */
+ unsigned int fillbytes1[124];
+ unsigned int physical_volume_id;
+ unsigned int fillbytes2[124];
+} aix_partition;
+
+#define AIX_LABEL_MAGIC 0xc9c2d4c1
+#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
+#define AIX_INFO_MAGIC 0x00072959
+#define AIX_INFO_MAGIC_SWAPPED 0x59290700
+
+/* fdisk.c */
+#define aixlabel ((aix_partition *)buffer)
+extern char buffer[MAX_SECTOR_SIZE];
+extern char changed[MAXIMUM_PARTS];
+extern uint heads, sectors, cylinders;
+extern int show_begin;
+extern int aix_label;
+extern char *partition_type(unsigned char type);
+extern void update_units(void);
+extern char read_chars(char *mesg);
+
+/* fdiskaixlabel.c */
+extern struct systypes aix_sys_types[];
+extern void aix_nolabel( void );
+extern int check_aix_label( void );
diff --git a/fdisk/fdiskbsdlabel.c b/fdisk/fdiskbsdlabel.c
new file mode 100644
index 000000000..8edec2331
--- /dev/null
+++ b/fdisk/fdiskbsdlabel.c
@@ -0,0 +1,825 @@
+/*
+ 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/hdreg.h> /* for HDIO_GETGEO */
+
+#include "fdisk.h"
+#define NETBSD_PARTITION 0xa5
+#define DKTYPENAMES
+#include "fdiskbsdlabel.h"
+
+static void xbsd_delete_part (void);
+static void xbsd_new_part (void);
+static void xbsd_print_disklabel (int show_all);
+static void xbsd_write_disklabel (void);
+static int xbsd_create_disklabel (void);
+static void xbsd_edit_disklabel (void);
+static void xbsd_write_bootstrap (void);
+static void xbsd_change_fstype (void);
+static int xbsd_get_part_index (int max);
+static int xbsd_check_new_partition (int *i);
+static void xbsd_list_types (void);
+static u_short xbsd_dkcksum (struct xbsd_disklabel *lp);
+static int xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex);
+static int xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d);
+static int xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d);
+static void sync_disks (void);
+#if defined (i386) || defined (sparc)
+static int xbsd_translate_fstype (int linux_type);
+static void xbsd_link_part (void);
+#endif
+#if defined (__alpha__)
+void alpha_bootblock_checksum (char *boot);
+#endif
+
+static struct xbsd_disklabel xbsd_dlabel;
+static char buffer[BSD_BBSIZE];
+#if defined (i386) || defined (sparc)
+static struct partition *xbsd_part;
+static int xbsd_part_index;
+#endif
+
+int
+btrydev (char * dev) {
+ if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
+ return -1;
+ printf("\nBSD label for device: %s\n", dev);
+ xbsd_print_disklabel (0);
+ return 0;
+}
+
+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) || defined (sparc)
+ " 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) || defined (sparc)
+ " x link BSD partition to non-BSD partition"
+#endif
+ );
+}
+
+int
+hidden(int type) {
+ return type ^ 0x10;
+}
+
+int
+is_netbsd_partition_type(int type) {
+ return (type == NETBSD_PARTITION || type == hidden(NETBSD_PARTITION));
+}
+
+void
+bselect (void) {
+#if defined (i386) || defined (sparc)
+ int t, ss;
+
+ for (t=0; t<4; t++)
+ if (is_netbsd_partition_type(part_table[t] -> sys_ind)) {
+ xbsd_part = part_table[t];
+ xbsd_part_index = t;
+ ss = get_start_sect(xbsd_part);
+ if (ss == 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, ss + BSD_LABELSECTOR);
+ if (xbsd_readlabel (xbsd_part, &xbsd_dlabel) == 0)
+ if (xbsd_create_disklabel () == 0)
+ return;
+ break;
+ }
+
+ if (t == 4) {
+ printf ("There is no *BSD partition on %s.\n", disk_device);
+ return;
+ }
+
+#elif defined (__alpha__)
+
+ if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
+ if (xbsd_create_disklabel () == 0)
+ exit ( EXIT_SUCCESS );
+
+#endif
+
+ while (1)
+ {
+ putchar ('\n');
+ switch (tolower (read_char ("BSD disklabel command (m for help): ")))
+ {
+ case 'd':
+ xbsd_delete_part ();
+ break;
+ case 'e':
+ xbsd_edit_disklabel ();
+ break;
+ case 'i':
+ xbsd_write_bootstrap ();
+ break;
+ case 'l':
+ xbsd_list_types ();
+ break;
+ case 'n':
+ xbsd_new_part ();
+ break;
+ case 'p':
+ xbsd_print_disklabel (0);
+ break;
+ case 'q':
+ close (fd);
+ exit ( EXIT_SUCCESS );
+ case 's':
+ xbsd_print_disklabel (1);
+ break;
+ case 't':
+ xbsd_change_fstype ();
+ break;
+ case 'w':
+ xbsd_write_disklabel ();
+ break;
+#if defined (i386) || defined (sparc)
+ case 'r':
+ return;
+ case 'x':
+ xbsd_link_part ();
+ break;
+#endif
+ default:
+ bmenu ();
+ break;
+ }
+ }
+}
+
+static void
+xbsd_delete_part (void)
+{
+ int i;
+
+ i = xbsd_get_part_index (xbsd_dlabel.d_npartitions);
+ xbsd_dlabel.d_partitions[i].p_size = 0;
+ xbsd_dlabel.d_partitions[i].p_offset = 0;
+ xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
+ if (xbsd_dlabel.d_npartitions == i + 1)
+ while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
+ xbsd_dlabel.d_npartitions--;
+}
+
+static void
+xbsd_new_part (void)
+{
+ uint begin, end;
+ char mesg[48];
+ int i;
+
+ if (!xbsd_check_new_partition (&i))
+ return;
+
+#if defined (i386) || defined (sparc)
+ begin = get_start_sect(xbsd_part);
+ end = begin + get_nr_sects(xbsd_part) - 1;
+#elif defined (__alpha__) || defined (__powerpc__)
+ begin = 0;
+ end = xbsd_dlabel.d_secperunit;
+#endif
+
+ sprintf (mesg, "First %s", str_units());
+ begin = read_int (cround (begin), cround (begin), cround (end),
+ 0, mesg);
+
+ sprintf (mesg, "Last %s or +size or +sizeM or +sizeK", str_units());
+ end = read_int (cround (begin), cround (end), cround (end),
+ cround (begin), mesg);
+
+ if (unit_flag)
+ {
+ begin = (begin - 1) * display_factor;
+ end = end * display_factor - 1;
+ }
+ xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
+ xbsd_dlabel.d_partitions[i].p_offset = begin;
+ xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
+}
+
+static void
+xbsd_print_disklabel (int show_all)
+{
+ struct xbsd_disklabel *lp = &xbsd_dlabel;
+ struct xbsd_partition *pp;
+ FILE *f = stdout;
+ int i, j;
+
+ if (show_all)
+ {
+#if defined (i386) || defined (sparc)
+ fprintf(f, "# %s%d:\n", disk_device, xbsd_part_index+1);
+#elif defined (__alpha__)
+ fprintf(f, "# %s:\n", disk_device);
+#endif
+ if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
+ fprintf(f, "type: %s\n", xbsd_dktypenames[lp->d_type]);
+ else
+ fprintf(f, "type: %d\n", lp->d_type);
+ fprintf(f, "disk: %.*s\n", (int) sizeof(lp->d_typename), lp->d_typename);
+ fprintf(f, "label: %.*s\n", (int) sizeof(lp->d_packname), lp->d_packname);
+ fprintf(f, "flags:");
+ if (lp->d_flags & BSD_D_REMOVABLE)
+ fprintf(f, " removable");
+ if (lp->d_flags & BSD_D_ECC)
+ fprintf(f, " ecc");
+ if (lp->d_flags & BSD_D_BADSECT)
+ fprintf(f, " badsect");
+ fprintf(f, "\n");
+ /* On various machines the fields of *lp are short/int/long */
+ /* In order to avoid problems, we cast them all to long. */
+ fprintf(f, "bytes/sector: %ld\n", (long) lp->d_secsize);
+ fprintf(f, "sectors/track: %ld\n", (long) lp->d_nsectors);
+ fprintf(f, "tracks/cylinder: %ld\n", (long) lp->d_ntracks);
+ fprintf(f, "sectors/cylinder: %ld\n", (long) lp->d_secpercyl);
+ fprintf(f, "cylinders: %ld\n", (long) lp->d_ncylinders);
+ fprintf(f, "rpm: %d\n", lp->d_rpm);
+ fprintf(f, "interleave: %d\n", lp->d_interleave);
+ fprintf(f, "trackskew: %d\n", lp->d_trackskew);
+ fprintf(f, "cylinderskew: %d\n", lp->d_cylskew);
+ fprintf(f, "headswitch: %ld\t\t# milliseconds\n", (long) lp->d_headswitch);
+ fprintf(f, "track-to-track seek: %ld\t# milliseconds\n", (long) lp->d_trkseek);
+ fprintf(f, "drivedata: ");
+ for (i = NDDATA - 1; i >= 0; i--)
+ if (lp->d_drivedata[i])
+ break;
+ if (i < 0)
+ i = 0;
+ for (j = 0; j <= i; j++)
+ fprintf(f, "%ld ", (long) lp->d_drivedata[j]);
+ }
+ fprintf (f, "\n%d partitions:\n", lp->d_npartitions);
+ fprintf (f, "# size offset fstype [fsize bsize cpg]\n");
+ pp = lp->d_partitions;
+ for (i = 0; i < lp->d_npartitions; i++, pp++) {
+ if (pp->p_size) {
+ fprintf(f, " %c: %8ld %8ld ", 'a' + i,
+ (long) pp->p_size, (long) pp->p_offset);
+ if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
+ fprintf(f, "%8.8s", xbsd_fstypes[pp->p_fstype].name);
+ else
+ fprintf(f, "%8x", pp->p_fstype);
+ switch (pp->p_fstype)
+ {
+ case BSD_FS_UNUSED:
+ fprintf(f, " %5ld %5ld %5.5s ",
+ (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
+ break;
+
+ case BSD_FS_BSDFFS:
+ fprintf(f, " %5ld %5ld %5d ",
+ (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag,
+ pp->p_cpg);
+ break;
+
+ default:
+ fprintf(f, "%20.20s", "");
+ break;
+ }
+ fprintf(f, "\t# (Cyl. %4ld", (long)
+#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, "- %ld",
+ (long) (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
+xbsd_write_disklabel (void)
+{
+#if defined (i386) || defined (sparc)
+ printf ("Writing disklabel to %s%d.\n", disk_device, xbsd_part_index+1);
+ xbsd_writelabel (xbsd_part, &xbsd_dlabel);
+#elif defined (__alpha__)
+ printf ("Writing disklabel to %s.\n", disk_device);
+ xbsd_writelabel (NULL, &xbsd_dlabel);
+#endif
+}
+
+static int
+xbsd_create_disklabel (void)
+{
+ char c;
+
+#if defined (i386) || defined (sparc)
+ fprintf (stderr, "%s%d contains no disklabel.\n",
+ disk_device, xbsd_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) || defined (sparc)
+ if (xbsd_initlabel (xbsd_part, &xbsd_dlabel, xbsd_part_index) == 1)
+#elif defined (__alpha__) || defined (__powerpc__)
+ if (xbsd_initlabel (NULL, &xbsd_dlabel, 0) == 1)
+#endif
+ {
+ xbsd_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
+xbsd_edit_disklabel (void)
+{
+ struct xbsd_disklabel *d;
+
+ d = &xbsd_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
+xbsd_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
+xbsd_write_bootstrap (void)
+{
+ char *bootdir = BSD_LINUX_BOOTDIR;
+ char path[MAXPATHLEN];
+ char *dkbasename;
+ struct xbsd_disklabel dl;
+ char *d, *p, *e;
+ int sector;
+
+ if (xbsd_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 (!xbsd_get_bootstrap (path, buffer, (int) xbsd_dlabel.d_secsize))
+ return;
+
+ /* We need a backup of the disklabel (xbsd_dlabel might have changed). */
+ d = &buffer[BSD_LABELSECTOR * SECTOR_SIZE];
+ bcopy (d, &dl, sizeof (struct xbsd_disklabel));
+
+ /* The disklabel will be overwritten by 0's from bootxx anyway */
+ bzero (d, sizeof (struct xbsd_disklabel));
+
+ sprintf (path, "%s/boot%s", bootdir, dkbasename);
+ if (!xbsd_get_bootstrap (path, &buffer[xbsd_dlabel.d_secsize],
+ (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
+ return;
+
+ e = d + sizeof (struct xbsd_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 xbsd_disklabel));
+
+#if defined (i386) || defined (sparc)
+ sector = get_start_sect(xbsd_part);
+#elif defined (__powerpc__)
+ sector = 0;
+#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) || defined (sparc)
+ printf ("Bootstrap installed on %s%d.\n", disk_device, xbsd_part_index+1);
+#elif defined (__alpha__)
+ printf ("Bootstrap installed on %s.\n", disk_device);
+#endif
+
+ sync_disks ();
+}
+
+static void
+xbsd_change_fstype (void)
+{
+ int i;
+
+ i = xbsd_get_part_index (xbsd_dlabel.d_npartitions);
+ xbsd_dlabel.d_partitions[i].p_fstype = read_hex (xbsd_fstypes);
+}
+
+static int
+xbsd_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
+xbsd_check_new_partition (int *i)
+{
+ int t;
+
+ if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS)
+ {
+ for (t=0; t < BSD_MAXPARTITIONS; t++)
+ if (xbsd_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 = xbsd_get_part_index (BSD_MAXPARTITIONS);
+
+ if (*i >= xbsd_dlabel.d_npartitions)
+ xbsd_dlabel.d_npartitions = (*i) + 1;
+
+ if (xbsd_dlabel.d_partitions[*i].p_size != 0)
+ {
+ fprintf (stderr, "This partition already exists.\n");
+ return 0;
+ }
+ return 1;
+}
+
+static void
+xbsd_list_types (void)
+{
+ list_types (xbsd_fstypes);
+}
+
+static u_short
+xbsd_dkcksum (struct xbsd_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
+xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex)
+{
+ struct hd_geometry geometry;
+ struct xbsd_partition *pp;
+
+ if (ioctl (fd, HDIO_GETGEO, &geometry) == -1)
+ {
+ perror ("ioctl");
+ return 0;
+ }
+ bzero (d, sizeof (struct xbsd_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) || defined (sparc)
+ 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) || defined (sparc)
+ d -> d_npartitions = 4;
+ pp = &d -> d_partitions[2]; /* Partition C should be the NetBSD partition */
+ pp -> p_offset = get_start_sect(p);
+ pp -> p_size = get_nr_sects(p);
+ 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
+xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
+{
+ int t, sector;
+
+#if defined (i386) || defined (sparc)
+ sector = (p ? get_start_sect(p) : 0);
+#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 xbsd_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
+xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
+{
+ int sector;
+
+#if defined (i386) || defined (sparc)
+ sector = get_start_sect(p) + BSD_LABELSECTOR;
+#elif defined (__alpha__) || defined (__powerpc__)
+ sector = BSD_LABELSECTOR;
+#endif
+
+ d -> d_checksum = 0;
+ d -> d_checksum = xbsd_dkcksum (d);
+
+ /* This is necessary if we want to write the bootstrap later,
+ otherwise we'd write the old disklabel with the bootstrap.
+ */
+ bcopy (d, &buffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
+ sizeof (struct xbsd_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 xbsd_disklabel) != write (fd, d, sizeof (struct xbsd_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) || defined (sparc)
+static int
+xbsd_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
+xbsd_link_part (void)
+{
+ int k, i;
+
+ k = get_partition (1, partitions);
+
+ if (!xbsd_check_new_partition (&i))
+ return;
+
+ xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(part_table[k]);
+ xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(part_table[k]);
+ xbsd_dlabel.d_partitions[i].p_fstype =
+ xbsd_translate_fstype (part_table[k] -> sys_ind);
+}
+#endif
+
+#if defined (__alpha__)
+
+#if 0
+typedef unsigned long long u_int64_t;
+#endif
+
+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/fdisk/fdiskbsdlabel.h b/fdisk/fdiskbsdlabel.h
new file mode 100644
index 000000000..b9f2c9c38
--- /dev/null
+++ b/fdisk/fdiskbsdlabel.h
@@ -0,0 +1,229 @@
+/*
+ * 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 <linux/types.h> /* for __u32 etc */
+
+#ifndef BSD_DISKMAGIC /* perhaps from <linux/genhd.h> */
+#define BSD_DISKMAGIC ((__u32) 0x82564557)
+#endif
+
+#ifndef BSD_MAXPARTITIONS
+#define BSD_MAXPARTITIONS 8
+#endif
+
+#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
+
+#if defined (i386) || defined (sparc)
+#define BSD_LABELSECTOR 1
+#define BSD_LABELOFFSET 0
+#elif defined (__alpha__) || defined (__powerpc__)
+#define BSD_LABELSECTOR 0
+#define BSD_LABELOFFSET 64
+#else
+#error unknown architecture
+#endif
+
+#define BSD_BBSIZE 8192 /* size of boot area, with label */
+#define BSD_SBSIZE 8192 /* max size of fs superblock */
+
+struct xbsd_disklabel {
+ __u32 d_magic; /* the magic number */
+ __s16 d_type; /* drive type */
+ __s16 d_subtype; /* controller/d_type specific */
+ char d_typename[16]; /* type name, e.g. "eagle" */
+ char d_packname[16]; /* pack identifier */
+ /* disk geometry: */
+ __u32 d_secsize; /* # of bytes per sector */
+ __u32 d_nsectors; /* # of data sectors per track */
+ __u32 d_ntracks; /* # of tracks per cylinder */
+ __u32 d_ncylinders; /* # of data cylinders per unit */
+ __u32 d_secpercyl; /* # of data sectors per cylinder */
+ __u32 d_secperunit; /* # of data sectors per unit */
+ /*
+ * Spares (bad sector replacements) below
+ * are not counted in d_nsectors or d_secpercyl.
+ * Spare sectors are assumed to be physical sectors
+ * which occupy space at the end of each track and/or cylinder.
+ */
+ __u16 d_sparespertrack; /* # of spare sectors per track */
+ __u16 d_sparespercyl; /* # of spare sectors per cylinder */
+ /*
+ * Alternate cylinders include maintenance, replacement,
+ * configuration description areas, etc.
+ */
+ __u32 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.
+ */
+ __u16 d_rpm; /* rotational speed */
+ __u16 d_interleave; /* hardware sector interleave */
+ __u16 d_trackskew; /* sector 0 skew, per track */
+ __u16 d_cylskew; /* sector 0 skew, per cylinder */
+ __u32 d_headswitch; /* head switch time, usec */
+ __u32 d_trkseek; /* track-to-track seek, usec */
+ __u32 d_flags; /* generic flags */
+#define NDDATA 5
+ __u32 d_drivedata[NDDATA]; /* drive-type specific information */
+#define NSPARE 5
+ __u32 d_spare[NSPARE]; /* reserved for future use */
+ __u32 d_magic2; /* the magic number (again) */
+ __u16 d_checksum; /* xor of data incl. partitions */
+ /* filesystem and partition information: */
+ __u16 d_npartitions; /* number of partitions in following */
+ __u32 d_bbsize; /* size of boot area at sn0, bytes */
+ __u32 d_sbsize; /* max size of fs superblock, bytes */
+ struct xbsd_partition { /* the partition table */
+ __u32 p_size; /* number of sectors in partition */
+ __u32 p_offset; /* starting sector */
+ __u32 p_fsize; /* filesystem basic fragment size */
+ __u8 p_fstype; /* filesystem type, see below */
+ __u8 p_frag; /* filesystem fragments per block */
+ __u16 p_cpg; /* filesystem cylinders per group */
+ } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
+};
+
+/* 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 *xbsd_dktypenames[] = {
+ "unknown",
+ "SMD",
+ "MSCP",
+ "old DEC",
+ "SCSI",
+ "ESDI",
+ "ST506",
+ "HP-IB",
+ "HP-FL",
+ "type 9",
+ "floppy",
+ 0
+};
+#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_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_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 */
+
+/* this is annoying, but it's also the way it is :-( */
+#ifdef __alpha__
+#define BSD_FS_EXT2 8 /* MS-DOS file system */
+#else
+#define BSD_FS_MSDOS 8 /* MS-DOS file system */
+#endif
+
+#ifdef DKTYPENAMES
+static struct systypes xbsd_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"},
+#ifdef __alpha__
+ {BSD_FS_EXT2, "ext2"},
+#else
+ {BSD_FS_MSDOS, "MS-DOS"},
+#endif
+ {BSD_FS_BSDLFS, "4.4LFS"},
+ {BSD_FS_OTHER, "unknown"},
+ {BSD_FS_HPFS, "HPFS"},
+ {BSD_FS_ISO9660,"ISO-9660"},
+ {BSD_FS_BOOT, "boot"},
+ {BSD_FS_ADOS, "ADOS"},
+ {BSD_FS_HFS, "HFS"},
+ { 0, NULL }
+};
+#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
+
+#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/fdisk/fdisksgilabel.c b/fdisk/fdisksgilabel.c
new file mode 100644
index 000000000..42f7363e4
--- /dev/null
+++ b/fdisk/fdisksgilabel.c
@@ -0,0 +1,888 @@
+/*
+ *
+ * fdisksgilabel.c
+ *
+ * Copyright (C) Andreas Neuper, Sep 1998.
+ * This file may be modified and redistributed under
+ * the terms of the GNU Public License.
+ */
+#include <stdio.h> /* stderr */
+#include <stdlib.h> /* uint */
+#include <string.h> /* strstr */
+#include <unistd.h> /* write */
+#include <sys/ioctl.h> /* ioctl */
+#include <sys/stat.h> /* stat */
+#include <assert.h> /* assert */
+
+#include <endian.h>
+#include <linux/major.h> /* FLOPPY_MAJOR */
+#include <linux/hdreg.h> /* HDIO_GETGEO */
+
+#include "fdisk.h"
+#include "fdisksgilabel.h"
+
+static int other_endian = 0;
+static int debug = 0;
+static short volumes=1;
+
+/*
+ * only dealing with free blocks here
+ */
+
+typedef struct { int first; int last; } freeblocks;
+static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
+void setfreelist( int i, int f, int l ) \
+ { freelist[i].first = f; freelist[i].last = l; return; }
+void add2freelist( int f, int l ) \
+ { int i = 0; for( ; i<17 ; i++ ) { if(freelist[i].last==0) break; }\
+ setfreelist( i, f, l ); return; }
+void clearfreelist( void ) \
+ { int i = 0; for( ; i<17 ; i++ ) { setfreelist( i, 0, 0 ); } return; }
+int isinfreelist( int b ) \
+ { int i = 0; for( ; i<17 ; i++ )\
+ { if( ( freelist[i].first <= b ) && ( freelist[i].last >= b) )\
+ { return freelist[i].last; } } return 0; }
+ /* return last vacant block of this stride (never 0). */
+ /* the '>=' is not quite correct, but simplifies the code */
+/*
+ * end of free blocks section
+ */
+
+struct systypes sgi_sys_types[] = {
+ {SGI_VOLHDR, "SGI volhdr"},
+ {0x01, "SGI trkrepl"},
+ {0x02, "SGI secrepl"},
+ {SGI_SWAP, "SGI raw"},
+ {0x04, "SGI bsd"},
+ {0x05, "SGI sysv"},
+ {ENTIRE_DISK, "SGI volume"},
+ {SGI_EFS, "SGI efs"},
+ {0x08, "SGI lvol"},
+ {0x09, "SGI rlvol"},
+ {0x0A, "SGI xfs"},
+ {0x0B, "SGI xlvol"},
+ {0x0C, "SGI rxlvol"},
+ {LINUX_SWAP, "Linux swap"},
+ {LINUX_NATIVE,"Linux native"},
+ {0, NULL }
+};
+
+static inline unsigned short __swap16(unsigned short x) {
+ return (((__u16)(x) & 0xFF) << 8) | (((__u16)(x) & 0xFF00) >> 8);
+}
+static inline __u32 __swap32(__u32 x) {
+ return (((__u32)(x) & 0xFF) << 24) | (((__u32)(x) & 0xFF00) << 8) | (((__u32)(x) & 0xFF0000) >> 8) | (((__u32)(x) & 0xFF000000) >> 24);
+}
+
+static
+int
+sgi_get_nsect( void )
+{
+ return SSWAP16(sgilabel->devparam.nsect);
+}
+
+static
+int
+sgi_get_ntrks( void )
+{
+ return SSWAP16(sgilabel->devparam.ntrks);
+}
+
+#if 0
+static int
+sgi_get_head_vol0( void )
+{
+ return SSWAP16(sgilabel->devparam.head_vol0);
+}
+
+static int
+sgi_get_bytes( void )
+{
+ return SSWAP16(sgilabel->devparam.bytes);
+}
+#endif
+
+static
+int
+sgi_get_pcylcount( void )
+{
+ return SSWAP16(sgilabel->devparam.pcylcount);
+}
+
+void
+sgi_nolabel()
+{
+ sgilabel->magic = 0;
+ sgi_label = 0;
+ partitions = 4;
+}
+
+unsigned int
+two_s_complement_32bit_sum(
+ unsigned int* base,
+ int size /* in bytes */ )
+{
+ int i=0;
+ unsigned int sum=0;
+ size = size / sizeof( unsigned int );
+ for( i=0; i<size; i++ )
+ {
+ sum = sum - SSWAP32(base[i]);
+ }
+ return sum;
+}
+
+int check_sgi_label()
+{
+ if (sizeof(sgilabel) > 512) {
+ fprintf(stderr,
+ "According to MIPS Computer Systems, Inc the "
+ "Label must not contain more than 512 bytes\n");
+ exit(1);
+ }
+
+ if (sgilabel->magic != SGI_LABEL_MAGIC &&
+ sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
+ sgi_label = 0;
+ other_endian = 0;
+ return 0;
+ }
+
+ other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
+ /*
+ * test for correct checksum
+ */
+ if( two_s_complement_32bit_sum( (unsigned int*)sgilabel,
+ sizeof(*sgilabel) ) )
+ {
+ fprintf( stderr, "Detected sgi disklabel with wrong checksum.\n" );
+ } else
+ {
+ heads = sgi_get_ntrks();
+ cylinders = sgi_get_pcylcount();
+ sectors = sgi_get_nsect();
+ }
+ update_units();
+ sgi_label = 1;
+ partitions= 16;
+ volumes = 15;
+ return 1;
+}
+
+void
+sgi_list_table( int xtra )
+{
+ int i, w;
+ char *type;
+
+ w = strlen( disk_device );
+
+ if( xtra )
+ {
+ printf( "\nDisk %s (SGI disk label): %d heads, %d sectors\n"
+ "%d cylinders, %d physical cylinders\n"
+ "%d extra sects/cyl, interleave %d:1\n"
+ "%s\n"
+ "Units = %ss of %d * 512 bytes\n\n",
+ disk_device, heads, sectors, cylinders,
+ SSWAP16(sgiparam.pcylcount),
+ SSWAP16(sgiparam.sparecyl),
+ SSWAP16(sgiparam.ilfact),
+ (char *)sgilabel,
+ str_units(), display_factor);
+ } else
+ {
+ printf( "\nDisk %s (SGI disk label): %d heads, %d sectors, %d cylinders\n"
+ "Units = %ss of %d * 512 bytes\n\n",
+ disk_device, heads, sectors, cylinders,
+ str_units(), display_factor );
+ }
+ printf("----- partitions -----\n"
+ "%*s Info Start End Sectors Id System\n",
+ w + 1, "Device");
+ for (i = 0 ; i < partitions; i++)
+ {
+ if( sgi_get_num_sectors(i) || debug )
+ {
+ __u32 start = sgi_get_start_sector(i);
+ __u32 len = sgi_get_num_sectors(i);
+ printf(
+ "%*s%-2d %4s %9ld %9ld %9ld %2x %s\n",
+/* device */ w, disk_device, i + 1,
+/* flags */ (sgi_get_swappartition() == i) ? "swap" :
+/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
+/* start */ (long) scround(start),
+/* end */ (long) scround(start+len)-1,
+/* no odd flag on end */ (long) len,
+/* type id */ sgi_get_sysid(i),
+/* type name */ (type = partition_type(sgi_get_sysid(i)))
+ ? type : "Unknown");
+ }
+ }
+ printf( "----- bootinfo -----\nBootfile: %s\n"
+ "----- directory entries -----\n",
+ sgilabel->boot_file );
+ for (i = 0 ; i < volumes; i++)
+ {
+ if (sgilabel->directory[i].vol_file_size)
+ {
+ __u32 start = SSWAP32(sgilabel->directory[i].vol_file_start);
+ __u32 len = SSWAP32(sgilabel->directory[i].vol_file_size);
+ char*name = sgilabel->directory[i].vol_file_name;
+ printf("%2d: %-10s sector%5u size%8u\n",
+ i, name, (unsigned int) start, (unsigned int) len);
+ }
+ }
+}
+
+int
+sgi_get_start_sector( int i )
+{
+ return SSWAP32(sgilabel->partitions[i].start_sector);
+}
+
+int
+sgi_get_num_sectors( int i )
+{
+ return SSWAP32(sgilabel->partitions[i].num_sectors);
+}
+
+int
+sgi_get_sysid( int i )
+{
+ return SSWAP32(sgilabel->partitions[i].id);
+}
+
+int
+sgi_get_bootpartition( void )
+{
+ return SSWAP16(sgilabel->boot_part);
+}
+
+int
+sgi_get_swappartition( void )
+{
+ return SSWAP16(sgilabel->swap_part);
+}
+
+void
+sgi_set_bootpartition( int i )
+{
+ sgilabel->boot_part = SSWAP16(((short)i));
+ return;
+}
+
+int
+sgi_get_lastblock( void )
+{
+ return heads * sectors * cylinders;
+}
+
+void
+sgi_set_swappartition( int i )
+{
+ sgilabel->swap_part = SSWAP16(((short)i));
+ return;
+}
+
+static int
+sgi_check_bootfile( const char* aFile )
+{
+ if( strlen( aFile ) < 3 ) /* "/a\n" is minimum */
+ {
+ printf( "\nInvalid Bootfile!\n"
+ "\tThe bootfile must be an absolute non-zero pathname,\n"
+ "\te.g. \"/unix\" or \"/unix.save\".\n" );
+ return 0;
+ } else
+ if( strlen( aFile ) > 16 )
+ {
+ printf( "\n\tName of Bootfile too long: 16 bytes maximum.\n" );
+ return 0;
+ } else
+ if( aFile[0] != '/' )
+ {
+ printf( "\n\tBootfile must have a fully qualified pathname.\n" );
+ return 0;
+ }
+ if( strncmp( aFile, sgilabel->boot_file, 16 ) )
+ {
+ printf( "\n\tBe aware, that the bootfile is not checked for existence.\n\t"
+ "SGI's default is \"/unix\" and for backup \"/unix.save\".\n" );
+ /* filename is correct and did change */
+ return 1;
+ }
+ return 0; /* filename did not change */
+}
+
+const char *
+sgi_get_bootfile(void) {
+ return sgilabel->boot_file;
+}
+
+void
+sgi_set_bootfile( const char* aFile )
+{
+ int i = 0;
+ if( sgi_check_bootfile( aFile ) )
+ {
+ while( i<16 )
+ {
+ if( (aFile[i] != '\n') /* in principle caught again by next line */
+ && (strlen( aFile ) > i ) )
+ sgilabel->boot_file[i] = aFile[i];
+ else
+ sgilabel->boot_file[i] = 0;
+ i++;
+ }
+ printf( "\n\tBootfile is changed to \"%s\".\n", sgilabel->boot_file );
+ }
+ return;
+}
+
+void
+create_sgiinfo( void )
+{
+ /* I keep SGI's habit to write the sgilabel to the second block */
+ sgilabel->directory[0].vol_file_start = SSWAP32( 2 );
+ sgilabel->directory[0].vol_file_size = SSWAP32( sizeof( sgiinfo ) );
+ strncpy( sgilabel->directory[0].vol_file_name, "sgilabel",8 );
+ return;
+}
+
+sgiinfo * fill_sgiinfo( void );
+
+void
+sgi_write_table( void )
+{
+ sgilabel->csum = 0;
+ sgilabel->csum = SSWAP32( two_s_complement_32bit_sum(
+ (unsigned int*)sgilabel,
+ sizeof(*sgilabel) ) );
+ assert( two_s_complement_32bit_sum(
+ (unsigned int*)sgilabel, sizeof(*sgilabel) ) == 0 );
+ if( lseek(fd, 0, SEEK_SET) < 0 )
+ fatal(unable_to_seek);
+ if( write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE )
+ fatal(unable_to_write);
+ if( ! strncmp( sgilabel->directory[0].vol_file_name, "sgilabel",8 ) )
+ {
+ /*
+ * keep this habbit of first writing the "sgilabel".
+ * I never tested whether it works without (AN 981002).
+ */
+ sgiinfo*info = fill_sgiinfo(); /* fills the block appropriately */
+ int infostartblock = SSWAP32( sgilabel->directory[0].vol_file_start );
+ if( ext2_llseek(fd, (ext2_loff_t)infostartblock*
+ SECTOR_SIZE, SEEK_SET) < 0 )
+ fatal(unable_to_seek);
+ if( write(fd, info, SECTOR_SIZE) != SECTOR_SIZE )
+ fatal(unable_to_write);
+ free( info );
+ }
+ return;
+}
+
+static
+int
+compare_start( int*x, int*y )
+{
+ /*
+ * sort according to start sectors
+ * and prefers largest partition:
+ * entry zero is entire disk entry
+ */
+ int i = *x;
+ int j = *y;
+ int a = sgi_get_start_sector(i);
+ int b = sgi_get_start_sector(j);
+ int c = sgi_get_num_sectors(i);
+ int d = sgi_get_num_sectors(j);
+ if( a == b )
+ {
+ return( d - c );
+ }
+ return( a - b );
+}
+
+static
+int
+sgi_gaps()
+{
+ /*
+ * returned value is:
+ * = 0 : disk is properly filled to the rim
+ * < 0 : there is an overlap
+ * > 0 : there is still some vacant space
+ */
+ return verify_sgi(0);
+}
+
+int
+verify_sgi( int verbose )
+{
+ int Index[16]; /* list of valid partitions */
+ int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
+ int compare_start();/* comparison function above */
+ int entire = 0, i = 0; /* local counters */
+ int start = 0;
+ int gap = 0; /* count unused blocks */
+ int lastblock = sgi_get_lastblock();
+ /*
+ */
+ clearfreelist();
+ for( i=0; i<16; i++ )
+ {
+ if( sgi_get_num_sectors(i)!=0 )
+ {
+ Index[sortcount++]=i;
+ if( sgi_get_sysid(i) == ENTIRE_DISK )
+ {
+ if( entire++ == 1 )
+ {
+ if(verbose)
+ printf("More than one entire disk entriy present.\n");
+ }
+ }
+ }
+ }
+ if( sortcount == 0 )
+ {
+ if(verbose)
+ printf("No partitions defined\n");
+ return lastblock;
+ }
+ qsort( Index, sortcount, sizeof(Index[0]), (void*)compare_start );
+ if( sgi_get_sysid( Index[0] ) == ENTIRE_DISK )
+ {
+ if( ( Index[0] != 10 ) && verbose )
+ printf( "IRIX likes when Partition 11 covers the entire disk.\n" );
+ if( ( sgi_get_start_sector( Index[0] ) != 0 ) && verbose )
+ printf( "The entire disk partition should start at block 0,\nnot "
+ "at diskblock %d.\n", sgi_get_start_sector(Index[0] ) );
+ if(debug) /* I do not understand how some disks fulfil it */
+ if( ( sgi_get_num_sectors( Index[0] ) != lastblock ) && verbose )
+ printf( "The entire disk partition is only %d diskblock large,\n"
+ "but the disk is %d diskblocks long.\n",
+ sgi_get_num_sectors( Index[0] ), lastblock );
+ lastblock = sgi_get_num_sectors( Index[0] );
+ } else
+ {
+ if( verbose )
+ printf( "One Partition (#11) should cover the entire disk.\n" );
+ if(debug>2)
+ printf( "sysid=%d\tpartition=%d\n",
+ sgi_get_sysid( Index[0] ), Index[0]+1 );
+ }
+ for( i=1, start=0; i<sortcount; i++ )
+ {
+ int cylsize = sgi_get_nsect() * sgi_get_ntrks();
+ if( (sgi_get_start_sector( Index[i] ) % cylsize) != 0 )
+ {
+ if(debug) /* I do not understand how some disks fulfil it */
+ if( verbose )
+ printf( "Partition %d does not start on cylinder boundary.\n",
+ Index[i]+1 );
+ }
+ if( sgi_get_num_sectors( Index[i] ) % cylsize != 0 )
+ {
+ if(debug) /* I do not understand how some disks fulfil it */
+ if( verbose )
+ printf( "Partition %d does not end on cylinder boundary.\n",
+ Index[i]+1 );
+ }
+ /* We cannot handle several "entire disk" entries. */
+ if( sgi_get_sysid( Index[i] ) == ENTIRE_DISK ) continue;
+ if( start > sgi_get_start_sector( Index[i] ) )
+ {
+ if( verbose )
+ printf( "The Partition %d and %d overlap by %d sectors.\n",
+ Index[i-1]+1, Index[i]+1,
+ start - sgi_get_start_sector( Index[i] ) );
+ if( gap > 0 ) gap = -gap;
+ if( gap == 0 ) gap = -1;
+ }
+ if( start < sgi_get_start_sector( Index[i] ) )
+ {
+ if( verbose )
+ printf( "Unused gap of %8d sectors - sectors %8d-%d\n",
+ sgi_get_start_sector( Index[i] ) - start,
+ start, sgi_get_start_sector( Index[i] )-1 );
+ gap += sgi_get_start_sector( Index[i] ) - start;
+ add2freelist( start, sgi_get_start_sector( Index[i] ) );
+ }
+ start = sgi_get_start_sector( Index[i] )
+ + sgi_get_num_sectors( Index[i] );
+ if(debug>1)
+ {
+ if( verbose )
+ printf( "%2d:%12d\t%12d\t%12d\n", Index[i],
+ sgi_get_start_sector(Index[i]),
+ sgi_get_num_sectors(Index[i]),
+ sgi_get_sysid(Index[i]) );
+ }
+ }
+ if( ( start < lastblock ) )
+ {
+ if( verbose )
+ printf( "Unused gap of %8d sectors - sectors %8d-%d\n",
+ lastblock - start, start, lastblock-1 );
+ gap += lastblock - start;
+ add2freelist( start, lastblock );
+ }
+ /*
+ * Done with arithmetics
+ * Go for details now
+ */
+ if( verbose )
+ {
+ if( !sgi_get_num_sectors( sgi_get_bootpartition() ) )
+ {
+ printf( "\nThe boot partition does not exist.\n" );
+ }
+ if( !sgi_get_num_sectors( sgi_get_swappartition() ) )
+ {
+ printf( "\nThe swap partition does not exist.\n" );
+ } else
+ if( ( sgi_get_sysid( sgi_get_swappartition() ) != SGI_SWAP )
+ && ( sgi_get_sysid( sgi_get_swappartition() ) != LINUX_SWAP ) )
+ {
+ printf( "\nThe swap partition has no swap type.\n" );
+ }
+ if( sgi_check_bootfile( "/unix" ) )
+ {
+ printf( "\tYou have chosen an unusual boot file name.\n" );
+ }
+ }
+ return gap;
+}
+
+void
+sgi_change_sysid( int i, int sys )
+{
+ if( sgi_get_num_sectors(i) == 0 ) /* caught already before, ... */
+ {
+ printf("Sorry You may change the Tag of non-empty partitions.\n");
+ return;
+ }
+ if( ((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
+ && (sgi_get_start_sector(i)<1) )
+ {
+ read_chars(
+ "It is highly recommended that the partition at offset 0\n"
+ "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
+ "retrieve from its directory standalone tools like sash and fx.\n"
+ "Only the \"SGI volume\" entire disk section may violate this.\n"
+ "Type YES if you are sure about tagging this partition differently.\n" );
+ if (strcmp (line_ptr, "YES\n"))
+ return;
+ }
+ sgilabel->partitions[i].id = SSWAP32(sys);
+ return;
+}
+
+int
+sgi_entire( void )
+{ /* returns partition index of first entry marked as entire disk */
+ int i=0;
+ for( i=0; i<16; i++ )
+ if( sgi_get_sysid(i) == SGI_VOLUME )
+ return i;
+ return -1;
+}
+
+int
+sgi_num_partitions( void )
+{
+ int i=0,
+ n=0;
+ for( i=0; i<16; i++ )
+ if( sgi_get_num_sectors(i)!=0 )
+ n++;
+ return n;
+}
+
+static
+void
+sgi_set_partition( int i, uint start, uint length, int sys )
+{
+ sgilabel->partitions[i].id =
+ SSWAP32( sys );
+ sgilabel->partitions[i].num_sectors =
+ SSWAP32( length );
+ sgilabel->partitions[i].start_sector =
+ SSWAP32( start );
+ changed[i] = 1;
+ if( sgi_gaps(0) < 0 ) /* rebuild freelist */
+ {
+ printf( "Do You know, You got a partition overlap on the disk?\n" );
+ }
+ return;
+}
+
+static
+void
+sgi_set_entire( void )
+{
+ int n;
+ for( n=10; n<partitions; n++ )
+ {
+ if(!sgi_get_num_sectors( n ) )
+ {
+ sgi_set_partition( n, 0, sgi_get_lastblock(), SGI_VOLUME );
+ break;
+ }
+ }
+ return;
+}
+
+static
+void
+sgi_set_volhdr( void )
+{
+ int n;
+ for( n=8; n<partitions; n++ )
+ {
+ if(!sgi_get_num_sectors( n ) )
+ {
+ /*
+ * 5 cylinders is an arbitrary value I like
+ * IRIX 5.3 stored files in the volume header
+ * (like sash, symmon, fx, ide) with ca. 3200
+ * sectors.
+ */
+ if( heads * sectors * 5 < sgi_get_lastblock() )
+ sgi_set_partition( n, 0, heads * sectors * 5, SGI_VOLHDR );
+ break;
+ }
+ }
+ return;
+}
+
+void
+sgi_delete_partition( int i )
+{
+ sgi_set_partition( i, 0, 0, 0 );
+ return;
+}
+
+void
+sgi_add_partition( int n, int sys )
+{
+ char mesg[48];
+ int first=0, last=0;
+
+ if( n == 10 ) {
+ sys = SGI_VOLUME;
+ } else if ( n == 8 ) {
+ sys = 0;
+ }
+ if( sgi_get_num_sectors(n) )
+ {
+ printf( "Partition %d is already defined. Delete "
+ "it before re-adding it.\n", n + 1);
+ return;
+ }
+ if( (sgi_entire() == -1)
+ && (sys != SGI_VOLUME) )
+ {
+ printf( "Attempting to generate entire disk entry automatically.\n" );
+ sgi_set_entire();
+ sgi_set_volhdr();
+ }
+ if( (sgi_gaps() == 0)
+ && (sys != SGI_VOLUME) )
+ {
+ printf( "The entire disk is already covered with partitions.\n" );
+ return;
+ }
+ if( sgi_gaps() < 0 )
+ {
+ printf( "You got a partition overlap on the disk. Fix it first!\n" );
+ return;
+ }
+ sprintf(mesg, "First %s", str_units());
+ for(;;)
+ {
+ if(sys == SGI_VOLUME)
+ {
+ last = sgi_get_lastblock();
+ first = read_int(0, 0, last-1, 0, mesg);
+ if( first != 0 ) {
+ printf( "It is highly recommended that eleventh partition\n"
+ "covers the entire disk and is of type `SGI volume'\n");
+ }
+ } else {
+ first = freelist[0].first;
+ last = freelist[0].last;
+ first = read_int(scround(first), scround(first), scround(last)-1,
+ 0, mesg);
+ }
+ if (unit_flag)
+ first *= display_factor;
+ else
+ first = first; /* align to cylinder if you know how ... */
+ if( !last )
+ last = isinfreelist(first);
+ if( last == 0 ) {
+ printf( "You will get a partition overlap on the disk. "
+ "Fix it first!\n" );
+ } else
+ break;
+ }
+ sprintf(mesg, " Last %s", str_units());
+ last = read_int(scround(first), scround(last)-1, scround(last)-1,
+ scround(first), mesg)+1;
+ if (unit_flag)
+ last *= display_factor;
+ else
+ last = last; /* align to cylinder if You know how ... */
+ if( (sys == SGI_VOLUME) && ( first != 0 || last != sgi_get_lastblock() ) )
+ {
+ printf( "It is highly recommended that eleventh partition\n"
+ "covers the entire disk and is of type `SGI volume'\n");
+ }
+ sgi_set_partition( n, first, last-first, sys );
+ return;
+}
+
+void
+create_sgilabel( void )
+{
+ struct hd_geometry geometry;
+ struct { int start;
+ int nsect;
+ int sysid; } old[4];
+ int i=0;
+ fprintf( stderr,
+ "Building a new SGI disklabel. Changes will remain in memory only,\n"
+ "until you decide to write them. After that, of course, the previous\n"
+ "content will be unrecoverable lost.\n\n");
+#if BYTE_ORDER == LITTLE_ENDIAN
+ other_endian = 1;
+#else
+ other_endian = 0;
+#endif
+#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;
+ }
+ for (i = 0; i < 4; i++)
+ {
+ old[i].sysid = 0;
+ if( valid_part_table_flag(buffer) )
+ {
+ if( part_table[i]->sys_ind )
+ {
+ old[i].sysid = part_table[i]->sys_ind;
+ old[i].start = get_start_sect( part_table[i] );
+ old[i].nsect = get_nr_sects( part_table[i] );
+ printf( "Trying to keep parameters of partition %d.\n", i );
+ if( debug )
+ printf( "ID=%02x\tSTART=%d\tLENGTH=%d\n",
+ old[i].sysid, old[i].start, old[i].nsect );
+ }
+ }
+ }
+ memset(buffer, 0, SECTOR_SIZE);
+ sgilabel->magic = SSWAP32(SGI_LABEL_MAGIC);
+ sgilabel->boot_part = SSWAP16(0);
+ sgilabel->swap_part = SSWAP16(1); strncpy(
+ sgilabel->boot_file , "/unix\0\0\0\0\0\0\0\0\0\0\0", 16 );
+ sgilabel->devparam.skew = (0);
+ sgilabel->devparam.gap1 = (0);
+ sgilabel->devparam.gap2 = (0);
+ sgilabel->devparam.sparecyl = (0);
+ sgilabel->devparam.pcylcount = SSWAP16(geometry.cylinders);
+ sgilabel->devparam.head_vol0 = SSWAP16(0);
+ sgilabel->devparam.ntrks = SSWAP16(geometry.heads);
+ /* tracks/cylinder (heads) */
+ sgilabel->devparam.cmd_tag_queue_depth = (0);
+ sgilabel->devparam.unused0 = (0);
+ sgilabel->devparam.unused1 = SSWAP16(0);
+ sgilabel->devparam.nsect = SSWAP16(geometry.sectors);
+ /* sectors/track */
+ sgilabel->devparam.bytes = SSWAP16(512);
+ sgilabel->devparam.ilfact = SSWAP16(1);
+ sgilabel->devparam.flags = SSWAP32(TRACK_FWD|\
+ IGNORE_ERRORS|RESEEK);
+ sgilabel->devparam.datarate = SSWAP32(0);
+ sgilabel->devparam.retries_on_error = SSWAP32(1);
+ sgilabel->devparam.ms_per_word = SSWAP32(0);
+ sgilabel->devparam.xylogics_gap1 = SSWAP16(0);
+ sgilabel->devparam.xylogics_syncdelay = SSWAP16(0);
+ sgilabel->devparam.xylogics_readdelay = SSWAP16(0);
+ sgilabel->devparam.xylogics_gap2 = SSWAP16(0);
+ sgilabel->devparam.xylogics_readgate = SSWAP16(0);
+ sgilabel->devparam.xylogics_writecont = SSWAP16(0);
+ memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
+ memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 );
+ sgi_label = 1;
+ partitions = 16;
+ volumes = 15;
+ sgi_set_entire();
+ sgi_set_volhdr();
+ for (i = 0; i < 4; i++)
+ {
+ if( old[i].sysid )
+ {
+ sgi_set_partition( i, old[i].start, old[i].nsect, old[i].sysid );
+ }
+ }
+ return;
+}
+
+void
+sgi_set_ilfact( void )
+{
+ /* do nothing in the beginning */
+}
+
+void
+sgi_set_rspeed( void )
+{
+ /* do nothing in the beginning */
+}
+
+void
+sgi_set_pcylcount( void )
+{
+ /* do nothing in the beginning */
+}
+
+void
+sgi_set_xcyl( void )
+{
+ /* do nothing in the beginning */
+}
+
+void
+sgi_set_ncyl( void )
+{
+ /* do nothing in the beginning */
+}
+
+/* _____________________________________________________________
+ */
+
+sgiinfo*
+fill_sgiinfo( void )
+{
+ sgiinfo*info=calloc( 1, sizeof(sgiinfo) );
+ info->magic=SSWAP32(SGI_INFO_MAGIC);
+ info->b1=SSWAP32(-1);
+ info->b2=SSWAP16(-1);
+ info->b3=SSWAP16(1);
+ /* You may want to replace this string !!!!!!! */
+ strcpy( info->scsi_string, "IBM OEM 0662S12 3 30" );
+ strcpy( info->serial, "0000" );
+ info->check1816 = SSWAP16(18*256 +16 );
+ strcpy( info->installer, "Sfx version 5.3, Oct 18, 1994" );
+ return info;
+}
diff --git a/fdisk/fdisksgilabel.h b/fdisk/fdisksgilabel.h
new file mode 100644
index 000000000..6eb7293f9
--- /dev/null
+++ b/fdisk/fdisksgilabel.h
@@ -0,0 +1,133 @@
+#include <linux/types.h> /* for __u32 etc */
+/*
+ * Copyright (C) Andreas Neuper, Sep 1998.
+ * This file may be modified and redistributed under
+ * the terms of the GNU Public License.
+ */
+
+struct device_parameter { /* 48 bytes */
+ unsigned char skew;
+ unsigned char gap1;
+ unsigned char gap2;
+ unsigned char sparecyl;
+ unsigned short pcylcount;
+ unsigned short head_vol0;
+ unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
+ unsigned char cmd_tag_queue_depth;
+ unsigned char unused0;
+ unsigned short unused1;
+ unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
+ unsigned short bytes;
+ unsigned short ilfact;
+ unsigned int flags; /* controller flags */
+ unsigned int datarate;
+ unsigned int retries_on_error;
+ unsigned int ms_per_word;
+ unsigned short xylogics_gap1;
+ unsigned short xylogics_syncdelay;
+ unsigned short xylogics_readdelay;
+ unsigned short xylogics_gap2;
+ unsigned short xylogics_readgate;
+ unsigned short xylogics_writecont;
+};
+
+#define SGI_VOLUME 0x06
+#define SGI_EFS 0x07
+#define SGI_SWAP 0x03
+#define SGI_VOLHDR 0x00
+#define ENTIRE_DISK SGI_VOLUME
+/*
+ * controller flags
+ */
+#define SECTOR_SLIP 0x01
+#define SECTOR_FWD 0x02
+#define TRACK_FWD 0x04
+#define TRACK_MULTIVOL 0x08
+#define IGNORE_ERRORS 0x10
+#define RESEEK 0x20
+#define ENABLE_CMDTAGQ 0x40
+
+typedef struct {
+ unsigned int magic; /* expect SGI_LABEL_MAGIC */
+ unsigned short boot_part; /* active boot partition */
+ unsigned short swap_part; /* active swap partition */
+ unsigned char boot_file[16]; /* name of the bootfile */
+ struct device_parameter devparam; /* 1 * 48 bytes */
+ struct volume_directory { /* 15 * 16 bytes */
+ unsigned char vol_file_name[8]; /* an character array */
+ unsigned int vol_file_start; /* number of logical block */
+ unsigned int vol_file_size; /* number of bytes */
+ } directory[15];
+ struct sgi_partition { /* 16 * 12 bytes */
+ unsigned int num_sectors; /* number of blocks */
+ unsigned int start_sector; /* sector must be cylinder aligned */
+ unsigned int id;
+ } partitions[16];
+ unsigned int csum;
+ unsigned int fillbytes;
+} sgi_partition;
+
+typedef struct {
+ unsigned int magic; /* looks like a magic number */
+ unsigned int a2;
+ unsigned int a3;
+ unsigned int a4;
+ unsigned int b1;
+ unsigned short b2;
+ unsigned short b3;
+ unsigned int c[16];
+ unsigned short d[3];
+ unsigned char scsi_string[50];
+ unsigned char serial[137];
+ unsigned short check1816;
+ unsigned char installer[225];
+} sgiinfo;
+
+#define SGI_LABEL_MAGIC 0x0be5a941
+#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
+#define SGI_INFO_MAGIC 0x00072959
+#define SGI_INFO_MAGIC_SWAPPED 0x59290700
+#define SSWAP16(x) (other_endian ? __swap16(x) \
+ : (__u16)(x))
+#define SSWAP32(x) (other_endian ? __swap32(x) \
+ : (__u32)(x))
+#define scround(x) ((x+(display_factor-1)*unit_flag)/display_factor)
+
+/* fdisk.c */
+#define sgilabel ((sgi_partition *)buffer)
+#define sgiparam (sgilabel->devparam)
+extern char buffer[MAX_SECTOR_SIZE];
+extern char changed[MAXIMUM_PARTS];
+extern uint heads, sectors, cylinders;
+extern int show_begin;
+extern int sgi_label;
+extern char *partition_type(unsigned char type);
+extern void update_units(void);
+extern char read_chars(char *mesg);
+
+/* fdisksgilabel.c */
+extern struct systypes sgi_sys_types[];
+extern void sgi_nolabel( void );
+extern int check_sgi_label( void );
+extern void sgi_list_table( int xtra );
+extern void sgi_change_sysid( int i, int sys );
+extern int sgi_get_start_sector( int i );
+extern int sgi_get_num_sectors( int i );
+extern int sgi_get_sysid( int i );
+extern void sgi_delete_partition( int i );
+extern void sgi_add_partition( int n, int sys );
+extern void create_sgilabel( void );
+extern void create_sgiinfo( void );
+extern int verify_sgi( int verbose );
+extern void sgi_write_table( void );
+extern void sgi_set_ilfact( void );
+extern void sgi_set_rspeed( void );
+extern void sgi_set_pcylcount( void );
+extern void sgi_set_xcyl( void );
+extern void sgi_set_ncyl( void );
+extern void sgi_set_bootpartition( int i );
+extern void sgi_set_swappartition( int i );
+extern int sgi_get_bootpartition( void );
+extern int sgi_get_swappartition( void );
+extern void sgi_set_bootfile( const char* aFile );
+extern const char *sgi_get_bootfile( void );
diff --git a/fdisk/fdisksunlabel.c b/fdisk/fdisksunlabel.c
new file mode 100644
index 000000000..708377379
--- /dev/null
+++ b/fdisk/fdisksunlabel.c
@@ -0,0 +1,690 @@
+/*
+ * fdisksunlabel.c
+ *
+ * I think this is mostly, or entirely, due to
+ * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
+ *
+ * Merged with fdisk for other architectures, aeb, June 1998.
+ */
+
+#include <stdio.h> /* stderr */
+#include <stdlib.h> /* uint */
+#include <string.h> /* strstr */
+#include <unistd.h> /* write */
+#include <sys/ioctl.h> /* ioctl */
+#include <sys/stat.h> /* stat */
+
+#include <endian.h>
+#if 1
+#include <scsi/scsi.h> /* SCSI_IOCTL_GET_IDLUN */
+#endif
+#include <linux/major.h> /* FLOPPY_MAJOR */
+#include <linux/hdreg.h> /* HDIO_GETGEO */
+
+#include "fdisk.h"
+#include "fdisksunlabel.h"
+
+static int other_endian = 0;
+static int scsi_disk = 0;
+static int floppy = 0;
+
+#define LINUX_SWAP 0x82
+#define LINUX_NATIVE 0x83
+
+struct systypes sun_sys_types[] = {
+ {0, "Empty"},
+ {1, "Boot"},
+ {2, "SunOS root"},
+ {SUNOS_SWAP, "SunOS swap"},
+ {4, "SunOS usr"},
+ {WHOLE_DISK, "Whole disk"},
+ {6, "SunOS stand"},
+ {7, "SunOS var"},
+ {8, "SunOS home"},
+ {LINUX_SWAP, "Linux swap"},
+ {LINUX_NATIVE, "Linux native"},
+ { 0, NULL }
+};
+
+static inline unsigned short __swap16(unsigned short x) {
+ return (((__u16)(x) & 0xFF) << 8) | (((__u16)(x) & 0xFF00) >> 8);
+}
+static inline __u32 __swap32(__u32 x) {
+ return (((__u32)(x) & 0xFF) << 24) | (((__u32)(x) & 0xFF00) << 8) | (((__u32)(x) & 0xFF0000) >> 8) | (((__u32)(x) & 0xFF000000) >> 24);
+}
+
+int
+get_num_sectors(struct sun_partition p) {
+ return SSWAP32(p.num_sectors);
+}
+
+void guess_device_type(int fd) {
+ struct stat bootstat;
+
+ if (fstat (fd, &bootstat) < 0) {
+ scsi_disk = 0;
+ floppy = 0;
+ } else if (S_ISBLK(bootstat.st_mode)
+ && ((bootstat.st_rdev >> 8) == IDE0_MAJOR ||
+ (bootstat.st_rdev >> 8) == IDE1_MAJOR)) {
+ scsi_disk = 0;
+ floppy = 0;
+ } else if (S_ISBLK(bootstat.st_mode)
+ && (bootstat.st_rdev >> 8) == FLOPPY_MAJOR) {
+ scsi_disk = 0;
+ floppy = 1;
+ } else {
+ scsi_disk = 1;
+ floppy = 0;
+ }
+}
+
+void set_sun_partition(int i, uint start, uint stop, int sysid)
+{
+ sunlabel->infos[i].id = sysid;
+ sunlabel->partitions[i].start_cylinder =
+ SSWAP32(start / (heads * sectors));
+ sunlabel->partitions[i].num_sectors =
+ SSWAP32(stop - start);
+ changed[i] = 1;
+}
+
+void sun_nolabel(void)
+{
+ sun_label = 0;
+ sunlabel->magic = 0;
+ partitions = 4;
+}
+
+int check_sun_label(void)
+{
+ unsigned short *ush;
+ int csum;
+
+ if (sunlabel->magic != SUN_LABEL_MAGIC &&
+ sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
+ sun_label = 0;
+ other_endian = 0;
+ return 0;
+ }
+ other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
+ ush = ((unsigned short *) (sunlabel + 1)) - 1;
+ for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
+ if (csum) {
+ fprintf(stderr, "Detected sun disklabel with wrong checksum.\n"
+ "Probably you'll have to set all the values,\n"
+ "e.g. heads, sectors, cylinders and partitions\n"
+ "or force a fresh label (s command in main menu)\n");
+ } else {
+ heads = SSWAP16(sunlabel->ntrks);
+ cylinders = SSWAP16(sunlabel->ncyl);
+ sectors = SSWAP16(sunlabel->nsect);
+ }
+ update_units();
+ sun_label = 1;
+ partitions = 8;
+ return 1;
+}
+
+struct sun_predefined_drives {
+ char *vendor;
+ char *model;
+ unsigned short sparecyl;
+ unsigned short ncyl;
+ unsigned short nacyl;
+ unsigned short pcylcount;
+ unsigned short ntrks;
+ unsigned short nsect;
+ unsigned short rspeed;
+} sun_drives[] = {
+{"Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
+{"Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
+{"CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
+{"","SUN0104",1,974,2,1019,6,35,3662},
+{"","SUN0207",4,1254,2,1272,9,36,3600},
+{"","SUN0327",3,1545,2,1549,9,46,3600},
+{"","SUN0340",0,1538,2,1544,6,72,4200},
+{"","SUN0424",2,1151,2,2500,9,80,4400},
+{"","SUN0535",0,1866,2,2500,7,80,5400},
+{"","SUN0669",5,1614,2,1632,15,54,3600},
+{"","SUN1.0G",5,1703,2,1931,15,80,3597},
+{"","SUN1.05",0,2036,2,2038,14,72,5400},
+{"","SUN1.3G",6,1965,2,3500,17,80,5400},
+{"","SUN2.1G",0,2733,2,3500,19,80,5400},
+{"IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
+};
+
+struct sun_predefined_drives *
+sun_autoconfigure_scsi() {
+ struct sun_predefined_drives *p = NULL;
+
+#ifdef SCSI_IOCTL_GET_IDLUN
+ unsigned int id[2];
+ char buffer[2048];
+ char buffer2[2048];
+ FILE *pfd;
+ char *vendor;
+ char *model;
+ char *q;
+ int i;
+
+ if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) {
+ sprintf(buffer,
+ "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
+#if 0
+ ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
+#else
+ /* This is very wrong (works only if you have one HBA),
+ but I haven't found a way how to get hostno
+ from the current kernel */
+ 0,
+#endif
+ (id[0]>>16)&0xff,
+ id[0]&0xff,
+ (id[0]>>8)&0xff);
+ pfd = fopen("/proc/scsi/scsi","r");
+ if (pfd) {
+ while (fgets(buffer2,2048,pfd)) {
+ if (!strcmp(buffer, buffer2)) {
+ if (fgets(buffer2,2048,pfd)) {
+ q = strstr(buffer2,"Vendor: ");
+ if (q) {
+ q += 8;
+ vendor = q;
+ q = strstr(q," Model: ");
+ if (q) {
+ *q = 0;
+ q += 8;
+ model = q;
+ q = strstr(q," Rev: ");
+ if (q) {
+ *q = 0;
+ for (i = 0; i < SIZE(sun_drives); i++) {
+ if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
+ continue;
+ if (!strstr(model, sun_drives[i].model))
+ continue;
+ printf("Autoconfigure found a %s%s%s\n",sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
+ p = sun_drives + i;
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ fclose(pfd);
+ }
+ }
+#endif
+ return p;
+}
+
+void create_sunlabel(void)
+{
+ struct hd_geometry geometry;
+ unsigned int ndiv;
+ int i;
+ unsigned char c;
+ struct sun_predefined_drives *p = NULL;
+
+ fprintf(stderr, "Building a new sun disklabel. Changes will remain in memory only,\n"
+ "until you decide to write them. After that, of course, the previous\n"
+ "content won't be recoverable.\n\n");
+#if BYTE_ORDER == LITTLE_ENDIAN
+ other_endian = 1;
+#else
+ other_endian = 0;
+#endif
+ memset(buffer, 0, SECTOR_SIZE);
+ sunlabel->magic = SSWAP16(SUN_LABEL_MAGIC);
+ if (!floppy) {
+ puts("Drive type\n"
+ " ? auto configure\n"
+ " 0 custom (with hardware detected defaults)");
+ for (i = 0; i < SIZE(sun_drives); i++) {
+ printf(" %c %s%s%s\n",
+ i + 'a', sun_drives[i].vendor,
+ (*sun_drives[i].vendor) ? " " : "",
+ sun_drives[i].model);
+ }
+ for (;;) {
+ c = read_char("Select type (? for auto, 0 for custom): ");
+ if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
+ p = sun_drives + c - 'a';
+ break;
+ } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
+ p = sun_drives + c - 'A';
+ break;
+ } else if (c == '0') {
+ break;
+ } else if (c == '?' && scsi_disk) {
+ p = sun_autoconfigure_scsi();
+ if (!p)
+ printf("Autoconfigure failed.\n");
+ else
+ break;
+ }
+ }
+ }
+ if (!p || floppy) {
+#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;
+ } else {
+ heads = 0;
+ sectors = 0;
+ cylinders = 0;
+ }
+ if (floppy) {
+ sunlabel->nacyl = 0;
+ sunlabel->pcylcount = SSWAP16(cylinders);
+ sunlabel->rspeed = SSWAP16(300);
+ sunlabel->ilfact = SSWAP16(1);
+ sunlabel->sparecyl = 0;
+ } else {
+ heads = read_int(1,heads,1024,0,"Heads");
+ sectors = read_int(1,sectors,1024,0,"Sectors/track");
+ if (cylinders)
+ cylinders = read_int(1,cylinders-2,65535,0,"Cylinders");
+ else
+ cylinders = read_int(1,0,65535,0,"Cylinders");
+ sunlabel->nacyl =
+ SSWAP16(read_int(0,2,65535,0,
+ "Alternate cylinders"));
+ sunlabel->pcylcount =
+ SSWAP16(read_int(0,cylinders+SSWAP16(sunlabel->nacyl),
+ 65535,0,"Physical cylinders"));
+ sunlabel->rspeed =
+ SSWAP16(read_int(1,5400,100000,0,
+ "Rotation speed (rpm)"));
+ sunlabel->ilfact =
+ SSWAP16(read_int(1,1,32,0,"Interleave factor"));
+ sunlabel->sparecyl =
+ SSWAP16(read_int(0,0,sectors,0,
+ "Extra sectors per cylinder"));
+ }
+ } else {
+ sunlabel->sparecyl = SSWAP16(p->sparecyl);
+ sunlabel->ncyl = SSWAP16(p->ncyl);
+ sunlabel->nacyl = SSWAP16(p->nacyl);
+ sunlabel->pcylcount = SSWAP16(p->pcylcount);
+ sunlabel->ntrks = SSWAP16(p->ntrks);
+ sunlabel->nsect = SSWAP16(p->nsect);
+ sunlabel->rspeed = SSWAP16(p->rspeed);
+ cylinders = p->ncyl;
+ heads = p->ntrks;
+ sectors = p->nsect;
+ puts("You may change all the disk params from the x menu");
+ }
+ sprintf(buffer, "%s%s%s cyl %d alt %d hd %d sec %d",
+ p ? p->vendor : "", (p && *p->vendor) ? " " : "", p ? p->model : (floppy ? "3,5\" floppy" : "Linux custom"),
+ cylinders, SSWAP16(sunlabel->nacyl), heads, sectors);
+ sunlabel->ntrks = SSWAP16(heads);
+ sunlabel->nsect = SSWAP16(sectors);
+ sunlabel->ncyl = SSWAP16(cylinders);
+ if (floppy)
+ set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
+ else {
+ if (cylinders * heads * sectors >= 150 * 2048) {
+ ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
+ } else
+ ndiv = cylinders * 2 / 3;
+ set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
+ set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
+ sunlabel->infos[1].flags |= 0x01; /* Not mountable */
+ }
+ set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK);
+ {
+ unsigned short *ush = (unsigned short *)sunlabel;
+ unsigned short csum = 0;
+ while(ush < (unsigned short *)(&sunlabel->csum))
+ csum ^= *ush++;
+ sunlabel->csum = csum;
+ }
+ for (i = 1; i < MAXIMUM_PARTS; i++)
+ changed[i] = 0;
+ changed[0] = 1;
+ get_boot(create_empty);
+}
+
+void toggle_sunflags(int i, unsigned char mask)
+{
+ if (sunlabel->infos[i].flags & mask)
+ sunlabel->infos[i].flags &= ~mask;
+ else sunlabel->infos[i].flags |= mask;
+ changed[i] = 1;
+}
+
+void fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
+{
+ int i, continuous = 1;
+ *start = 0; *stop = cylinders * heads * sectors;
+ for (i = 0; i < partitions; i++) {
+ if (sunlabel->partitions[i].num_sectors && sunlabel->infos[i].id && sunlabel->infos[i].id != WHOLE_DISK) {
+ starts[i] = SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
+ lens[i] = SSWAP32(sunlabel->partitions[i].num_sectors);
+ if (continuous) {
+ if (starts[i] == *start)
+ *start += lens[i];
+ else if (starts[i] + lens[i] >= *stop)
+ *stop = starts[i];
+ else
+ continuous = 0; /* There will be probably more gaps than one, so lets check afterwards */
+ }
+ } else {
+ starts[i] = 0;
+ lens[i] = 0;
+ }
+ }
+}
+
+static uint *verify_sun_starts;
+int verify_sun_cmp(int *a, int *b)
+{
+ if (*a == -1) return 1;
+ if (*b == -1) return -1;
+ if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
+ return -1;
+}
+
+void verify_sun(void)
+{
+ uint starts[8], lens[8], start, stop;
+ int i,j,k,starto,endo;
+ int array[8];
+
+ verify_sun_starts = starts;
+ fetch_sun(starts,lens,&start,&stop);
+ for (k = 0; k < 7; k++) {
+ for (i = 0; i < 8; i++) {
+ if (k && (lens[i] % (heads * sectors))) {
+ printf("Partition %d doesn't end on cylinder boundary\n", i+1);
+ }
+ if (lens[i]) {
+ for (j = 0; j < i; j++)
+ if (lens[j]) {
+ if (starts[j] == starts[i]+lens[i]) {
+ starts[j] = starts[i]; lens[j] += lens[i];
+ lens[i] = 0;
+ } else if (starts[i] == starts[j]+lens[j]){
+ lens[j] += lens[i];
+ lens[i] = 0;
+ } else if (!k) {
+ if (starts[i] < starts[j]+lens[j] &&
+ starts[j] < starts[i]+lens[i]) {
+ starto = starts[i];
+ if (starts[j] > starto)
+ starto = starts[j];
+ endo = starts[i]+lens[i];
+ if (starts[j]+lens[j] < endo)
+ endo = starts[j]+lens[j];
+ printf("Partition %d overlaps with others in "
+ "sectors %d-%d\n", i+1, starto, endo);
+ }
+ }
+ }
+ }
+ }
+ }
+ for (i = 0; i < 8; i++) {
+ if (lens[i])
+ array[i] = i;
+ else
+ array[i] = -1;
+ }
+ qsort(array,SIZE(array),sizeof(array[0]),
+ (int (*)(const void *,const void *)) verify_sun_cmp);
+ if (array[0] == -1) {
+ printf("No partitions defined\n");
+ return;
+ }
+ stop = cylinders * heads * sectors;
+ if (starts[array[0]])
+ printf("Unused gap - sectors 0-%d\n",starts[array[0]]);
+ for (i = 0; i < 7 && array[i+1] != -1; i++) {
+ printf("Unused gap - sectors %d-%d\n",starts[array[i]]+lens[array[i]],starts[array[i+1]]);
+ }
+ start = starts[array[i]]+lens[array[i]];
+ if (start < stop)
+ printf("Unused gap - sectors %d-%d\n",start,stop);
+}
+
+void add_sun_partition(int n, int sys)
+{
+ uint start, stop, stop2;
+ uint starts[8], lens[8];
+ int whole_disk = 0;
+
+ char mesg[48];
+ int i, first, last;
+
+ if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
+ printf("Partition %d is already defined. Delete "
+ "it before re-adding it.\n", n + 1);
+ return;
+ }
+
+ fetch_sun(starts,lens,&start,&stop);
+ if (stop <= start) {
+ if (n == 2)
+ whole_disk = 1;
+ else {
+ printf("Other partitions already cover the whole disk.\nDelete "
+ "some/shrink them before retry.\n");
+ return;
+ }
+ }
+ sprintf(mesg, "First %s", str_units());
+ for (;;) {
+ if (whole_disk)
+ first = read_int(0, 0, 0, 0, mesg);
+ else
+ first = read_int(scround(start), scround(stop)+1,
+ scround(stop), 0, mesg);
+ if (unit_flag)
+ first *= display_factor;
+ else
+ /* Starting sector has to be properly aligned */
+ first = (first + heads * sectors - 1) / (heads * sectors);
+ if (n == 2 && first != 0)
+ printf ("\
+It is highly recommended that the third partition covers the whole disk\n\
+and is of type `Whole disk'\n");
+ for (i = 0; i < partitions; i++)
+ if (lens[i] && starts[i] <= first
+ && starts[i] + lens[i] > first)
+ break;
+ if (i < partitions && !whole_disk) {
+ if (n == 2 && !first) {
+ whole_disk = 1;
+ break;
+ }
+ printf("Sector %d is already allocated\n", first);
+ } else
+ break;
+ }
+ stop = cylinders * heads * sectors;
+ stop2 = stop;
+ for (i = 0; i < partitions; i++) {
+ if (starts[i] > first && starts[i] < stop)
+ stop = starts[i];
+ }
+ sprintf(mesg, "Last %s or +size or +sizeM or +sizeK", str_units());
+ if (whole_disk)
+ last = read_int(scround(stop2), scround(stop2), scround(stop2),
+ 0, mesg);
+ else if (n == 2 && !first)
+ last = read_int(scround(first), scround(stop2), scround(stop2),
+ scround(first), mesg);
+ else
+ last = read_int(scround(first), scround(stop), scround(stop),
+ scround(first), mesg);
+ if (unit_flag)
+ last *= display_factor;
+ if (n == 2 && !first) {
+ if (last >= stop2) {
+ whole_disk = 1;
+ last = stop2;
+ } else if (last > stop) {
+ printf ("You haven't covered whole disk with 3rd partition, but your value\n"
+ "%d %s coveres some other partition. Your entry have been changed\n"
+ "to %d %s\n", scround(last), str_units(), scround(stop), str_units());
+ last = stop;
+ }
+ } else if (!whole_disk && last > stop)
+ last = stop;
+
+ if (whole_disk) sys = WHOLE_DISK;
+ set_sun_partition(n, first, last, sys);
+}
+
+void
+sun_delete_partition(int i) {
+ if (i == 2 && sunlabel->infos[i].id == WHOLE_DISK &&
+ !sunlabel->partitions[i].start_cylinder &&
+ SSWAP32(sunlabel->partitions[i].num_sectors)
+ == heads * sectors * cylinders)
+ printf("If you want to maintain SunOS/Solaris compatibility, "
+ "consider leaving this\n"
+ "partition as Whole disk (5), starting at 0, with %u "
+ "sectors\n",
+ (uint) SSWAP32(sunlabel->partitions[i].num_sectors));
+ sunlabel->infos[i].id = 0;
+ sunlabel->partitions[i].num_sectors = 0;
+}
+
+void
+sun_change_sysid(int i, int sys) {
+ if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
+ read_chars(
+ "It is highly recommended that the partition at offset 0\n"
+ "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
+ "there may destroy your partition table and bootblock.\n"
+ "Type YES if you're very sure you would like that partition\n"
+ "tagged with 82 (Linux swap): ");
+ if (strcmp (line_ptr, "YES\n"))
+ return;
+ }
+ switch (sys) {
+ case SUNOS_SWAP:
+ case LINUX_SWAP:
+ /* swaps are not mountable by default */
+ sunlabel->infos[i].flags |= 0x01;
+ break;
+ default:
+ /* assume other types are mountable;
+ user can change it anyway */
+ sunlabel->infos[i].flags &= ~0x01;
+ break;
+ }
+ sunlabel->infos[i].id = sys;
+}
+
+void
+sun_list_table(int xtra) {
+ int i, w;
+ char *type;
+
+ w = strlen(disk_device);
+ if (xtra)
+ printf("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
+ "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
+ "%d extra sects/cyl, interleave %d:1\n"
+ "%s\n"
+ "Units = %ss of %d * 512 bytes\n\n",
+ disk_device, heads, sectors, SSWAP16(sunlabel->rspeed),
+ cylinders, SSWAP16(sunlabel->nacyl),
+ SSWAP16(sunlabel->pcylcount),
+ SSWAP16(sunlabel->sparecyl),
+ SSWAP16(sunlabel->ilfact),
+ (char *)sunlabel,
+ str_units(), display_factor);
+ else
+ printf("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
+ "Units = %ss of %d * 512 bytes\n\n",
+ disk_device, heads, sectors, cylinders,
+ str_units(), display_factor);
+
+ printf("%*s Flag Start End Blocks Id System\n",
+ w + 1, "Device");
+ for (i = 0 ; i < partitions; i++) {
+ if (sunlabel->partitions[i].num_sectors) {
+ __u32 start = SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
+ __u32 len = SSWAP32(sunlabel->partitions[i].num_sectors);
+ printf(
+ "%*s%-2d %c%c %9ld %9ld %9ld%c %2x %s\n",
+/* device */ w, disk_device, i + 1,
+/* flags */ (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ',
+ (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
+/* start */ (long) scround(start),
+/* end */ (long) scround(start+len),
+/* odd flag on end */ (long) len / 2, len & 1 ? '+' : ' ',
+/* type id */ sunlabel->infos[i].id,
+/* type name */ (type = partition_type(sunlabel->infos[i].id))
+ ? type : "Unknown");
+ }
+ }
+}
+
+void
+sun_set_alt_cyl(void) {
+ sunlabel->nacyl =
+ SSWAP16(read_int(0,SSWAP16(sunlabel->nacyl), 65535, 0,
+ "Number of alternate cylinders"));
+}
+
+void
+sun_set_ncyl(int cyl) {
+ sunlabel->ncyl = SSWAP16(cyl);
+}
+
+void
+sun_set_xcyl(void) {
+ sunlabel->sparecyl =
+ SSWAP16(read_int(0, SSWAP16(sunlabel->sparecyl), sectors, 0,
+ "Extra sectors per cylinder"));
+}
+
+void
+sun_set_ilfact(void) {
+ sunlabel->ilfact =
+ SSWAP16(read_int(1, SSWAP16(sunlabel->ilfact), 32, 0,
+ "Interleave factor"));
+}
+
+void
+sun_set_rspeed(void) {
+ sunlabel->rspeed =
+ SSWAP16(read_int(1, SSWAP16(sunlabel->rspeed), 100000, 0,
+ "Rotation speed (rpm)"));
+}
+
+void
+sun_set_pcylcount(void) {
+ sunlabel->pcylcount =
+ SSWAP16(read_int(0, SSWAP16(sunlabel->pcylcount), 65535, 0,
+ "Number of physical cylinders"));
+}
+
+void
+sun_write_table(void) {
+ unsigned short *ush = (unsigned short *)sunlabel;
+ unsigned short csum = 0;
+
+ while(ush < (unsigned short *)(&sunlabel->csum))
+ csum ^= *ush++;
+ sunlabel->csum = csum;
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ fatal(unable_to_seek);
+ if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
+ fatal(unable_to_write);
+}
+
diff --git a/fdisk/fdisksunlabel.h b/fdisk/fdisksunlabel.h
new file mode 100644
index 000000000..d9d3706d3
--- /dev/null
+++ b/fdisk/fdisksunlabel.h
@@ -0,0 +1,74 @@
+#include <linux/types.h> /* for __u32 etc */
+
+typedef struct {
+ unsigned char info[128]; /* Informative text string */
+ unsigned char spare0[14];
+ struct sun_info {
+ unsigned char spare1;
+ unsigned char id;
+ unsigned char spare2;
+ unsigned char flags;
+ } infos[8];
+ unsigned char spare1[246]; /* Boot information etc. */
+ unsigned short rspeed; /* Disk rotational speed */
+ unsigned short pcylcount; /* Physical cylinder count */
+ unsigned short sparecyl; /* extra sects per cylinder */
+ unsigned char spare2[4]; /* More magic... */
+ unsigned short ilfact; /* Interleave factor */
+ unsigned short ncyl; /* Data cylinder count */
+ unsigned short nacyl; /* Alt. cylinder count */
+ unsigned short ntrks; /* Tracks per cylinder */
+ unsigned short nsect; /* Sectors per track */
+ unsigned char spare3[4]; /* Even more magic... */
+ struct sun_partition {
+ __u32 start_cylinder;
+ __u32 num_sectors;
+ } partitions[8];
+ unsigned short magic; /* Magic number */
+ unsigned short csum; /* Label xor'd checksum */
+} sun_partition;
+
+#define SUN_LABEL_MAGIC 0xDABE
+#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
+#define sunlabel ((sun_partition *)buffer)
+#define SSWAP16(x) (other_endian ? __swap16(x) \
+ : (__u16)(x))
+#define SSWAP32(x) (other_endian ? __swap32(x) \
+ : (__u32)(x))
+
+#define scround(x) ((x+(display_factor-1)*unit_flag)/display_factor)
+
+/* fdisk.c */
+extern char changed[MAXIMUM_PARTS];
+extern char buffer[MAX_SECTOR_SIZE];
+extern uint heads, sectors, cylinders;
+extern int show_begin;
+extern int sun_label;
+extern char *partition_type(unsigned char type);
+extern void update_units(void);
+extern char read_chars(char *mesg);
+
+/* fdisksunlabel.c */
+#define SUNOS_SWAP 3
+#define WHOLE_DISK 5
+
+extern struct systypes sun_sys_types[];
+extern int get_num_sectors(struct sun_partition p);
+extern void guess_device_type(int fd);
+extern int check_sun_label(void);
+extern void sun_nolabel(void);
+extern void create_sunlabel(void);
+extern void sun_delete_partition(int i);
+extern void sun_change_sysid(int i, int sys);
+extern void sun_list_table(int xtra);
+extern void verify_sun(void);
+extern void add_sun_partition(int n, int sys);
+extern void sun_write_table(void);
+extern void sun_set_alt_cyl(void);
+extern void sun_set_ncyl(int cyl);
+extern void sun_set_xcyl(void);
+extern void sun_set_ilfact(void);
+extern void sun_set_rspeed(void);
+extern void sun_set_pcylcount(void);
+extern void toggle_sunflags(int i, unsigned char mask);
+
diff --git a/fdisk/llseek.c b/fdisk/llseek.c
new file mode 100644
index 000000000..a9cd5a3ac
--- /dev/null
+++ b/fdisk/llseek.c
@@ -0,0 +1,102 @@
+/*
+ * llseek.c -- stub calling the llseek system call
+ *
+ * Copyright (C) 1994 Remy Card. This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <unistd.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, ext2_loff_t, unsigned int);
+
+#ifdef __linux__
+
+#ifdef HAVE_LLSEEK
+#include <syscall.h>
+
+#else /* HAVE_LLSEEK */
+
+#ifdef __alpha__
+
+#define my_llseek lseek
+
+#else
+#include <linux/unistd.h> /* for __NR__llseek */
+
+static int _llseek (unsigned int, unsigned long,
+ unsigned long, ext2_loff_t *, unsigned int);
+
+static _syscall5(int,_llseek,unsigned int,fd,unsigned long,offset_high,
+ unsigned long, offset_low,ext2_loff_t *,result,
+ unsigned int, origin)
+
+static ext2_loff_t my_llseek (unsigned int fd, ext2_loff_t offset,
+ unsigned int origin)
+{
+ ext2_loff_t result;
+ int retval;
+
+ retval = _llseek (fd, ((unsigned long long) offset) >> 32,
+ ((unsigned long long) offset) & 0xffffffff,
+ &result, origin);
+ return (retval == -1 ? (ext2_loff_t) retval : result);
+}
+
+#endif /* __alpha__ */
+
+#endif /* HAVE_LLSEEK */
+
+ext2_loff_t ext2_llseek (unsigned int fd, ext2_loff_t offset,
+ unsigned int origin)
+{
+ ext2_loff_t result;
+ static int do_compat = 0;
+
+ if (!do_compat) {
+ result = my_llseek (fd, offset, origin);
+ if (!(result == -1 && errno == ENOSYS))
+ return result;
+
+ /*
+ * Just in case this code runs on top of an old kernel
+ * which does not support the llseek system call
+ */
+ do_compat = 1;
+ /*
+ * Now try ordinary lseek.
+ */
+ }
+
+ if ((sizeof(off_t) >= sizeof(ext2_loff_t)) ||
+ (offset < ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1))))
+ return lseek(fd, (off_t) offset, origin);
+
+ errno = EINVAL;
+ return -1;
+}
+
+#else /* !linux */
+
+ext2_loff_t ext2_llseek (unsigned int fd, ext2_loff_t offset,
+ unsigned int origin)
+{
+ if ((sizeof(off_t) < sizeof(ext2_loff_t)) &&
+ (offset >= ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))) {
+ errno = EINVAL;
+ return -1;
+ }
+ return lseek (fd, (off_t) offset, origin);
+}
+
+#endif /* linux */
+
+
diff --git a/fdisk/sfdisk.8 b/fdisk/sfdisk.8
new file mode 100644
index 000000000..e7f3e82b6
--- /dev/null
+++ b/fdisk/sfdisk.8
@@ -0,0 +1,506 @@
+.\" Copyright 1995 Andries E. Brouwer (aeb@cwi.nl)
+.\" May be distributed under the GNU General Public License
+.\" The `DOS 6.x Warning' was taken from the old fdisk.8, which says
+.\" -- Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu)
+.\" -- May be distributed under the GNU General Public License
+.\" The `DRDOS Warning' was taken from a net post by Stephen Tweedie.
+.\"
+.TH SFDISK 8 "1 September 1995" "Linux 1.3.23" "Linux Programmer's Manual"
+.SH NAME
+sfdisk \- Partition table manipulator for Linux
+.SH SYNOPSIS
+.BR sfdisk " [options] device"
+.br
+.BR "sfdisk \-s " [partition]
+.SH DESCRIPTION
+.B sfdisk
+has four (main) uses: list the size of a partition, list the partitions
+on a device, check the partitions on a device, and - very dangerous -
+repartition a device.
+
+.SS "List Sizes"
+.BI "sfdisk \-s " partition
+gives the size of
+.I partition
+in blocks. This may be useful in connection with programs like
+.B mkswap
+or so. Here
+.I partition
+is usually something like
+.I /dev/hda1
+or
+.IR /dev/sdb12 ,
+but may also be an entire disk, like
+.IR /dev/xda .
+.br
+.RS
+.nf
+.if t .ft CW
+% sfdisk \-s /dev/hda9
+81599
+%
+.if t .ft R
+.fi
+.RE
+If the partition argument is omitted,
+.B sfdisk
+will list the sizes of all disks, and the total:
+.br
+.RS
+.nf
+.if t .ft CW
+% sfdisk \-s
+/dev/hda: 208896
+/dev/hdb: 1025136
+/dev/hdc: 1031063
+/dev/sda: 8877895
+/dev/sdb: 1758927
+total: 12901917 blocks
+%
+.if t .ft R
+.fi
+.RE
+
+.SS "List Partitions"
+The second type of invocation:
+.BI "sfdisk \-l " "[options] device"
+will list the partitions on this device.
+If the device argument is omitted, the partitions on all hard disks
+are listed.
+.br
+.nf
+.if t .ft CW
+% sfdisk \-l /dev/hdc
+
+Disk /dev/hdc: 16 heads, 63 sectors, 2045 cylinders
+Units = cylinders of 516096 bytes, blocks of 1024 bytes, counting from 0
+
+ Device Boot Start End #cyls #blocks Id System
+/dev/hdc1 0+ 406 407\- 205096+ 83 Linux native
+/dev/hdc2 407 813 407 205128 83 Linux native
+/dev/hdc3 814 2044 1231 620424 83 Linux native
+/dev/hdc4 0 \- 0 0 0 Empty
+%
+.if t .ft R
+.fi
+The trailing \- and + signs indicate that rounding has taken place,
+and that the actual value is slightly less (more).
+To see the exact values, ask for a listing with sectors as unit.
+
+.SS "Check partitions"
+The third type of invocation:
+.BI "sfdisk \-V " device
+will apply various consistency checks to the partition tables on
+.IR device .
+It prints `OK' or complains. The \-V option can be used together
+with \-l. In a shell script one might use
+.BI "sfdisk \-V \-q " device
+which only returns a status.
+
+.SS "Create partitions"
+The fourth type of invocation:
+.BI "sfdisk " device
+will cause
+.B sfdisk
+to read the specification for the desired partitioning of
+.I device
+from its standard input, and then to change the partition tables
+on that disk. Thus, it is possible to use
+.B sfdisk
+from a shell script. When
+.B sfdisk
+determines that its standard input is a terminal, it will be
+conversational; otherwise it will abort on any error.
+.LP
+BE EXTREMELY CAREFUL - ONE TYPING MISTAKE AND ALL YOUR DATA IS LOST
+.LP
+As a precaution, one can save the sectors changed by
+.BR sfdisk :
+.RS
+.nf
+.if t .ft CW
+% sfdisk /dev/hdd \-O hdd-partition-sectors.save
+\&...
+%
+.if t .ft R
+.fi
+.RE
+.LP
+Then, if you discover that you did something stupid before anything
+else has been written to disk, it may be possible to recover
+the old situation with
+.RS
+.nf
+.if t .ft CW
+% sfdisk /dev/hdd \-I hdd-partition-sectors.save
+%
+.if t .ft R
+.fi
+.RE
+.LP
+(This is not the same as saving the old partition table:
+a readable version of the old partition table can be saved
+using the \-d option. However, if you create logical partitions,
+the sectors describing them are located somewhere on disk,
+possibly on sectors that were not part of the partition table
+before. Thus, the information the \-O option saves is not a binary
+version of the output of \-d.)
+
+There are many options.
+
+.SH OPTIONS
+.TP
+.BR \-v " or " \-\-version
+Print version number of
+.B sfdisk
+and exit immediately.
+.TP
+.BR \-? " or " \-\-help
+Print a usage message and exit immediately.
+.TP
+.BR \-T " or " \-\-list-types
+Print the recognized types (system Id's).
+.TP
+.BR \-s " or " \-\-show\-size
+List the size of a partition.
+.TP
+.BR \-g " or " \-\-show\-geometry
+List the kernel's idea of the geometry of the indicated disk(s).
+.TP
+.BR \-l " or " \-\-list
+List the partitions of a device.
+.TP
+.BR \-d
+Dump the partitions of a device in a format useful as input
+to sfdisk. For example,
+.br
+.nf
+.if t .ft CW
+ % sfdisk -d /dev/hda > hda.out
+ % sfdisk /dev/hda < hda.out
+.if t .ft R
+.fi
+will correct the bad last extended partition that the OS/2
+fdisk creates.
+.TP
+.BR \-V " or " \-\-verify
+Test whether partitions seem correct. (See above.)
+.TP
+.BR \-i " or " \-\-increment
+Number cylinders etc. starting from 1 instead of 0.
+.TP
+.BI \-N " number"
+Change only the single partition indicated. For example:
+.br
+.nf
+.if t .ft CW
+ % sfdisk /dev/hdb \-N5
+ ,,,*
+ %
+.if t .ft R
+.fi
+will make the fifth partition on /dev/hdb bootable (`active')
+and change nothing else. (Probably this fifth partition
+is called /dev/hdb5, but you are free to call it something else,
+like `/my_equipment/disks/2/5' or so).
+.TP
+.BI \-A "number"
+Make the indicated partition(s) active, and all others inactive.
+.TP
+.BI \-c " or " \-\-id " number [Id]"
+If no Id argument given: print the partition Id of the indicated
+partition. If an Id argument is present: change the type (Id) of
+the indicated partition to the given value.
+This option has the two very long forms \-\-print\-id and \-\-change\-id.
+For example:
+.br
+.nf
+.if t .ft CW
+ % sfdisk --print-id /dev/hdb 5
+ 6
+ % sfdisk --change-id /dev/hdb 5 83
+ OK
+.if t .ft R
+.fi
+first reports that /dev/hdb5 has Id 6, and then changes that into 83.
+.TP
+.BR \-uS " or " \-uB " or " \-uC " or " \-uM
+Accept or report in units of sectors (blocks, cylinders, megabytes,
+respectively). The default is cylinders, at least when the geometry
+is known.
+.TP
+.BR \-x " or " \-\-show\-extended
+Also list non-primary extended partitions on output,
+and expect descriptors for them on input.
+.TP
+.BI \-C " cylinders"
+Specify the number of cylinders, possibly overriding what the kernel thinks.
+.TP
+.BI \-H " heads"
+Specify the number of heads, possibly overriding what the kernel thinks.
+.TP
+.BI \-S " sectors"
+Specify the number of sectors, possibly overriding what the kernel thinks.
+.TP
+.BR \-f " or " \-\-force
+Do what I say, even if it is stupid.
+.TP
+.BR \-q " or " \-\-quiet
+Suppress warning messages.
+.TP
+.BR \-L " or " \-\-Linux
+Do not complain about things irrelevant for Linux.
+.TP
+.BR \-D " or " \-\-DOS
+For DOS-compatibility: waste a little space.
+(More precisely: if a partition cannot contain sector 0,
+e.g. because that is the MBR of the device, or contains
+the partition table of an extended partition, then
+.B sfdisk
+would make it start the next sector. However, when this
+option is given it skips to the start of the next track,
+wasting for example 33 sectors (in case of 34 sectors/track),
+just like certain versions of DOS do.)
+Certain Disk Managers and boot loaders (such as OSBS, but not
+LILO or the OS/2 Boot Manager) also live in this empty space,
+so maybe you want this option if you use one.
+.TP
+.BR \-\-IBM " or " \-\-leave\-last
+Certain IBM diagnostic programs assume that they can use the
+last cylinder on a disk for disk-testing purposes. If you think
+you might ever run such programs, use this option to tell
+.B sfdisk
+that it should not allocate the last cylinder.
+Sometimes the last cylinder contains a bad sector table.
+.TP
+.B \-n
+Go through all the motions, but do not actually write to disk.
+.TP
+.B \-R
+Only execute the BLKRRPART ioctl (to make the kernel re-read
+the partition table). This can be useful for checking in advance
+that the final BLKRRPART will be successful, and also when you
+changed the partition table `by hand' (e.g., using dd from a backup).
+If the kernel complains (`device busy for revalidation (usage = 2)')
+then something still uses the device, and you still have to unmount
+some file system, or say swapoff to some swap partition.
+.TP
+.B \-\-no\-reread
+When starting a repartitioning of a disk, sfdisk checks that this disk
+is not mounted, or in use as a swap device, and refuses to continue
+if it is. This option suppresses the test. (On the other hand, the \-f
+option would force sfdisk to continue even when this test fails.)
+.TP
+.BI \-O " file"
+Just before writing the new partition, output the sectors
+that are going to be overwritten to
+.I file
+(where hopefully
+.I file
+resides on another disk, or on a floppy).
+.TP
+.BI \-I " file"
+After destroying your filesystems with an unfortunate
+.B sfdisk
+command, you would have been able to restore the old situation
+if only you had preserved it using the \-O flag.
+
+.SH THEORY
+Block 0 of a disk (the Master Boot Record) contains among
+other things four partition descriptors. The partitions
+described here are called
+.I primary
+partitions.
+.LP
+A partition descriptor has 6 fields:
+.br
+.nf
+.RS
+struct partition {
+ unsigned char bootable; /* 0 or 0x80 */
+ hsc begin_hsc;
+ unsigned char id;
+ hsc end_hsc;
+ unsigned int starting_sector;
+ unsigned int nr_of_sectors;
+}
+.RE
+.fi
+.LP
+The two hsc fields indicate head, sector and cylinder of the
+begin and the end of the partition. Since each hsc field only
+takes 3 bytes, only 24 bits are available, which does not
+suffice for big disks (say > 8GB). In fact, due to the wasteful
+representation (that uses a byte for the number of heads, which
+is typically 16), problems already start with 0.5GB.
+However Linux does not use these fields, and problems can arise
+only at boot time, before Linux has been started. For more
+details, see the
+.B lilo
+documentation.
+.LP
+Each partition has a type, its `Id', and if this type is 5
+.IR "" "(`" "extended partition" "')"
+the starting sector of the partition
+again contains 4 partition descriptors. MSDOS only uses the
+first two of these: the first one an actual data partition,
+and the second one again an extended partition (or empty).
+In this way one gets a chain of extended partitions.
+Other operating systems have slightly different conventions.
+Linux also accepts type 85 as equivalent to 5 - this can be
+useful if one wants to have extended partitions under Linux past
+the 1024 cylinder boundary, without DOS FDISK hanging.
+(If there is no good reason, you should just use 5, which is
+understood by other systems.)
+.LP
+Partitions that are not primary or extended are called
+.IR logical .
+Often, one cannot boot from logical partitions (because the
+process of finding them is more involved than just looking
+at the MBR).
+Note that of an extended partition only the Id and the start
+are used. There are various conventions about what to write
+in the other fields. One should not try to use extended partitions
+for data storage or swap.
+
+.SH "INPUT FORMAT"
+.B sfdisk
+reads lines of the form
+.br
+.RS
+<start> <size> <id> <bootable> <c,h,s> <c,h,s>
+.RE
+where each line fills one partition descriptor.
+.LP
+Fields are separated by whitespace, or comma or semicolon possibly
+followed by whitespace; initial and trailing whitespace is ignored.
+Numbers can be octal, decimal or hexadecimal, decimal is default.
+When a field is absent or empty, a default value is used.
+.LP
+The <c,h,s> parts can (and probably should) be omitted -
+.B sfdisk
+computes them from <start> and <size> and the disk geometry
+as given by the kernel or specified using the \-H, \-S, \-C flags.
+.LP
+Bootable is specified as [*|\-], with as default not-bootable.
+(The value of this field is irrelevant for Linux - when Linux
+runs it has been booted already - but might play a role for
+certain boot loaders and for other operating systems.
+For example, when there are several primary DOS partitions,
+DOS assigns C: to the first among these that is bootable.)
+.LP
+Id is given in hex, without the 0x prefix, or is [E|S|L|X], where
+L (LINUX_NATIVE (83)) is the default, S is LINUX_SWAP (82), E
+is EXTENDED_PARTITION (5), and X is LINUX_EXTENDED (85).
+.LP
+The default value of start is the first nonassigned sector/cylinder/...
+.LP
+The default value of size is as much as possible (until next
+partition or end-of-disk).
+.LP
+However, for the four partitions inside an extended partition,
+the defaults are: Linux partition, Extended partition, Empty, Empty.
+.LP
+But when the \-N option (change a single partition only) is given,
+the default for each field is its previous value.
+
+.SH EXAMPLE
+The command
+.RS
+.nf
+.if t .ft CW
+sfdisk /dev/hdc << EOF
+0,407
+,407
+;
+;
+EOF
+.if t .ft R
+.fi
+.RE
+will partition /dev/hdc just as indicated above.
+
+With the \-x option, the number of input lines must be a multiple of 4:
+you have to list the two empty partitions that you never want
+using two blank lines. Without the \-x option, you give one line
+for the partitions inside a extended partition, instead of four,
+and terminate with end-of-file (^D).
+(And
+.B sfdisk
+will assume that your input line represents the first of four,
+that the second one is extended, and the 3rd and 4th are empty.)
+
+.SH "DOS 6.x WARNING"
+
+The DOS 6.x FORMAT command looks for some information in the first
+sector of the data area of the partition, and treats this information
+as more reliable than the information in the partition table. DOS
+FORMAT expects DOS FDISK to clear the first 512 bytes of the data area
+of a partition whenever a size change occurs. DOS FORMAT will look at
+this extra information even if the /U flag is given -- we consider
+this a bug in DOS FORMAT and DOS FDISK.
+.LP
+The bottom line is that if you use sfdisk to change the size of a
+DOS partition table entry, then you must also use
+.B dd
+to zero the first 512 bytes of that partition before using DOS FORMAT to
+format the partition. For example, if you were using sfdisk to make a DOS
+partition table entry for /dev/hda1, then (after exiting sfdisk and
+rebooting Linux so that the partition table information is valid) you
+would use the command "dd if=/dev/zero of=/dev/hda1 bs=512 count=1" to zero
+the first 512 bytes of the partition.
+.B BE EXTREMELY CAREFUL
+if you use the
+.B dd
+command, since a small typo can make all of the data on your disk useless.
+
+For best results, you should always use an OS-specific partition table
+program. For example, you should make DOS partitions with the DOS FDISK
+program and Linux partitions with the Linux sfdisk program.
+
+.SH "DRDOS WARNINGS"
+
+Stephen Tweedie reported (930515): `Most reports of superblock
+corruption turn out to be due to bad partitioning, with one filesystem
+overrunning the start of the next and corrupting its superblock.
+I have even had this problem with the supposedly-reliable DRDOS. This
+was quite possibly due to DRDOS-6.0's FDISK command. Unless I created
+a blank track or cylinder between the DRDOS partition and the
+immediately following one, DRDOS would happily stamp all over the
+start of the next partition. Mind you, as long as I keep a little
+free disk space after any DRDOS partition, I don't have any other
+problems with the two coexisting on the one drive.'
+
+A. V. Le Blanc writes in README.esfdisk: `Dr. DOS 5.0 and 6.0 has been
+reported to have problems cooperating with Linux, and with this version
+of efdisk in particular. This efdisk sets the system type
+to hexadecimal 81. Dr. DOS seems to confuse
+this with hexadecimal 1, a DOS code. If you use Dr. DOS, use the
+efdisk command 't' to change the system code of any Linux partitions
+to some number less than hexadecimal 80; I suggest 41 and 42 for
+the moment.'
+
+A. V. Le Blanc writes in his README.fdisk: `DR-DOS 5.0 and 6.0
+are reported to have difficulties with partition ID codes of 80 or more.
+The Linux `fdisk' used to set the system type
+of new partitions to hexadecimal 81. DR-DOS seems to confuse this with
+hexadecimal 1, a DOS code. The values 82 for swap and 83 for file
+systems should not cause problems with DR-DOS. If they do, you may use
+the `fdisk' command `t' to change the system code of any Linux
+partitions to some number less than hexadecimal 80; I suggest 42 and 43
+for the moment.'
+
+In fact, it seems that only 4 bits are significant for the DRDOS FDISK,
+so that for example 11 and 21 are listed as DOS 2.0. However, DRDOS
+itself seems to use the full byte. I have not been able to reproduce
+any corruption with DRDOS or its fdisk.
+
+.SH BUGS
+A corresponding interactive
+.B cfdisk
+(with curses interface) is still lacking.
+.LP
+There are too many options.
+
+.SH AUTHOR
+A. E. Brouwer (aeb@cwi.nl)
diff --git a/fdisk/sfdisk.c b/fdisk/sfdisk.c
new file mode 100644
index 000000000..c3f470f89
--- /dev/null
+++ b/fdisk/sfdisk.c
@@ -0,0 +1,2864 @@
+/*
+ * sfdisk version 3.0 - aeb - 950813
+ *
+ * Copyright (C) 1995 Andries E. Brouwer (aeb@cwi.nl)
+ *
+ * This program is free software. You can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation: either Version 1
+ * or (at your option) any later version.
+ *
+ * A.V. Le Blanc (LeBlanc@mcc.ac.uk) wrote Linux fdisk 1992-1994,
+ * patched by various people (faith@cs.unc.edu, martin@cs.unc.edu,
+ * leisner@sdsp.mc.xerox.com, esr@snark.thyrsus.com, aeb@cwi.nl)
+ * 1993-1995, with version numbers (as far as I have seen) 0.93 - 2.0e.
+ * This program had (head,sector,cylinder) as basic unit, and was
+ * (therefore) broken in several ways for the use on larger disks -
+ * for example, my last patch (from 2.0d to 2.0e) was required
+ * to allow a partition to cross cylinder 8064, and to write an
+ * extended partition past the 4GB mark.
+ *
+ * The current program is a rewrite from scratch, and I started a
+ * version numbering at 3.0.
+ * Andries Brouwer, aeb@cwi.nl, 950813
+ *
+ * Well, a good user interface is still lacking. On the other hand,
+ * many configurations cannot be handled by any other fdisk.
+ * I changed the name to sfdisk to prevent confusion. - aeb, 970501
+ */
+
+#define PROGNAME "sfdisk"
+#define VERSION "3.07"
+#define DATE "980518"
+
+#include <stdio.h>
+#include <stdlib.h> /* atoi, free */
+#include <stdarg.h> /* varargs */
+#include <unistd.h> /* read, write */
+#include <fcntl.h> /* O_RDWR */
+#include <errno.h> /* ERANGE */
+#include <string.h> /* index() */
+#include <ctype.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <linux/unistd.h> /* _syscall */
+#include <linux/hdreg.h> /* HDIO_GETGEO */
+#include <linux/fs.h> /* BLKGETSIZE */
+
+#define SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+/*
+ * Table of contents:
+ * A. About seeking
+ * B. About sectors
+ * C. About heads, sectors and cylinders
+ * D. About system Ids
+ * E. About partitions
+ * F. The standard input
+ * G. The command line
+ * H. Listing the current situation
+ * I. Writing the new situation
+ */
+int exit_status = 0;
+
+int force = 0; /* 1: do what I say, even if it is stupid ... */
+int quiet = 0; /* 1: suppress all warnings */
+int Linux = 0; /* 1: suppress warnings irrelevant for Linux */
+int DOS = 0; /* 1: shift extended partitions by #sectors, not 1 */
+int dump = 0; /* 1: list in a format suitable for later input */
+int verify = 0; /* 1: check that listed partition is reasonable */
+int no_write = 0; /* 1: do not actually write to disk */
+int no_reread = 0; /* 1: skip the BLKRRPART ioctl test at startup */
+int leave_last = 0; /* 1: don't allocate the last cylinder */
+int opt_list = 0;
+char *save_sector_file = NULL;
+char *restore_sector_file = NULL;
+
+void
+warn(char *s, ...) {
+ va_list p;
+
+ va_start(p, s);
+ fflush(stdout);
+ if (!quiet)
+ vfprintf (stderr, s, p);
+ va_end(p);
+}
+
+void
+error(char *s, ...) {
+ va_list p;
+
+ va_start(p, s);
+ fflush(stdout);
+ fprintf(stderr, "\n" PROGNAME ": ");
+ vfprintf(stderr, s, p);
+ va_end(p);
+}
+
+void
+fatal(char *s, ...) {
+ va_list p;
+
+ va_start(p, s);
+ fflush(stdout);
+ fprintf(stderr, "\n" PROGNAME ": ");
+ vfprintf(stderr, s, p);
+ va_end(p);
+ exit(1);
+}
+
+/*
+ * A. About seeking
+ */
+
+/*
+ * sseek: seek to specified sector - return 0 on failure
+ *
+ * For >4GB disks lseek needs a > 32bit arg, and we have to use llseek.
+ * On the other hand, a 32 bit sector number is OK until 2TB.
+ * The routines _llseek and sseek below are the only ones that
+ * know about the loff_t type.
+ */
+#ifndef __alpha__
+static
+_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
+ loff_t *, res, uint, wh);
+#endif
+
+int
+sseek(char *dev, unsigned int fd, unsigned long s) {
+ loff_t in, out;
+ in = ((loff_t) s << 9);
+ out = 1;
+
+#ifndef __alpha__
+ if (_llseek (fd, in>>32, in & 0xffffffff, &out, SEEK_SET) != 0) {
+#else
+ if ((out = lseek(fd, in, SEEK_SET)) != in) {
+#endif
+ perror("llseek");
+ error("seek error on %s - cannot seek to %lu\n", dev, s);
+ return 0;
+ }
+
+ if (in != out) {
+ error("seek error: wanted 0x%08x%08x, got 0x%08x%08x\n",
+ (uint)(in>>32), (uint)(in & 0xffffffff),
+ (uint)(out>>32), (uint)(out & 0xffffffff));
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * B. About sectors
+ */
+
+/*
+ * We preserve all sectors read in a chain - some of these will
+ * have to be modified and written back.
+ */
+struct sector {
+ struct sector *next;
+ unsigned long sectornumber;
+ int to_be_written;
+ char data[512];
+} *sectorhead;
+
+void
+free_sectors(void) {
+ struct sector *s;
+
+ while (sectorhead) {
+ s = sectorhead;
+ sectorhead = s->next;
+ free(s);
+ }
+}
+
+struct sector *
+get_sector(char *dev, int fd, unsigned long sno) {
+ struct sector *s;
+
+ for(s = sectorhead; s; s = s->next)
+ if(s->sectornumber == sno)
+ return s;
+
+ if (!sseek(dev, fd, sno))
+ return 0;
+
+ if (!(s = (struct sector *) malloc(sizeof(struct sector))))
+ fatal("out of memory - giving up\n");
+
+ if (read(fd, s->data, sizeof(s->data)) != sizeof(s->data)) {
+ perror("read");
+ error("read error on %s - cannot read sector %lu\n", dev, sno);
+ free(s);
+ return 0;
+ }
+
+ s->next = sectorhead;
+ sectorhead = s;
+ s->sectornumber = sno;
+ s->to_be_written = 0;
+
+ return s;
+}
+
+int
+msdos_signature (struct sector *s) {
+ if (*(unsigned short *) (s->data + 0x1fe) != 0xaa55) {
+ error("ERROR: sector %lu does not have an msdos signature\n",
+ s->sectornumber);
+ return 0;
+ }
+ return 1;
+}
+
+int
+write_sectors(char *dev, int fd) {
+ struct sector *s;
+
+ for (s = sectorhead; s; s = s->next)
+ if (s->to_be_written) {
+ if (!sseek(dev, fd, s->sectornumber))
+ return 0;
+ if (write(fd, s->data, sizeof(s->data)) != sizeof(s->data)) {
+ perror("write");
+ error("write error on %s - cannot write sector %lu\n",
+ dev, s->sectornumber);
+ return 0;
+ }
+ s->to_be_written = 0;
+ }
+ return 1;
+}
+
+void
+ulong_to_chars(unsigned long u, char *uu) {
+ int i;
+
+ for(i=0; i<4; i++) {
+ uu[i] = (u & 0xff);
+ u >>= 8;
+ }
+}
+
+unsigned long
+chars_to_ulong(unsigned char *uu) {
+ int i;
+ unsigned long u = 0;
+
+ for(i=3; i>=0; i--)
+ u = (u << 8) | uu[i];
+ return u;
+}
+
+int
+save_sectors(char *dev, int fdin) {
+ struct sector *s;
+ char ss[516];
+ int fdout;
+
+ fdout = open(save_sector_file, O_WRONLY | O_CREAT, 0444);
+ if (fdout < 0) {
+ perror(save_sector_file);
+ error("cannot open partition sector save file (%s)\n",
+ save_sector_file);
+ return 0;
+ }
+
+ for (s = sectorhead; s; s = s->next)
+ if (s->to_be_written) {
+ ulong_to_chars(s->sectornumber, ss);
+ if (!sseek(dev, fdin, s->sectornumber))
+ return 0;
+ if (read(fdin, ss+4, 512) != 512) {
+ perror("read");
+ error("read error on %s - cannot read sector %lu\n",
+ dev, s->sectornumber);
+ return 0;
+ }
+ if (write(fdout, ss, sizeof(ss)) != sizeof(ss)) {
+ perror("write");
+ error("write error on %s\n", save_sector_file);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+void reread_disk_partition(char *dev, int fd);
+
+int
+restore_sectors(char *dev) {
+ int fdin, fdout, ct;
+ struct stat statbuf;
+ char *ss0, *ss;
+ unsigned long sno;
+
+ if (stat(restore_sector_file, &statbuf) < 0) {
+ perror(restore_sector_file);
+ error("cannot stat partition restore file (%s)\n",
+ restore_sector_file);
+ return 0;
+ }
+ if (statbuf.st_size % 516) {
+ error("partition restore file has wrong size - not restoring\n");
+ return 0;
+ }
+ if (!(ss = (char *) malloc(statbuf.st_size))) {
+ error("out of memory?\n");
+ return 0;
+ }
+ fdin = open(restore_sector_file, O_RDONLY);
+ if (fdin < 0) {
+ perror(restore_sector_file);
+ error("cannot open partition restore file (%s)\n",
+ restore_sector_file);
+ return 0;
+ }
+ if (read(fdin, ss, statbuf.st_size) != statbuf.st_size) {
+ perror("read");
+ error("error reading %s\n", restore_sector_file);
+ return 0;
+ }
+
+ fdout = open(dev, O_WRONLY);
+ if (fdout < 0) {
+ perror(dev);
+ error("cannot open device %s for writing\n", dev);
+ return 0;
+ }
+
+ ss0 = ss;
+ ct = statbuf.st_size/516;
+ while(ct--) {
+ sno = chars_to_ulong(ss);
+ if (!sseek(dev, fdout, sno))
+ return 0;
+ if (write(fdout, ss+4, 512) != 512) {
+ perror(dev);
+ error("error writing sector %lu on %s\n", sno, dev);
+ return 0;
+ }
+ ss += 516;
+ }
+ free(ss0);
+
+ reread_disk_partition(dev, fdout);
+
+ return 1;
+}
+
+/*
+ * C. About heads, sectors and cylinders
+ */
+
+/*
+ * <linux/hdreg.h> defines HDIO_GETGEO and
+ * struct hd_geometry {
+ * unsigned char heads;
+ * unsigned char sectors;
+ * unsigned short cylinders;
+ * unsigned long start;
+ * };
+ */
+
+unsigned long cylindersize;
+unsigned long heads, sectors, cylinders;
+unsigned long specified_heads, specified_sectors, specified_cylinders;
+
+void
+get_cylindersize(char *dev, int fd, int silent) {
+ struct hd_geometry g;
+ int ioctl_ok = 0;
+
+ heads = sectors = cylinders = 0;
+
+ if (!ioctl(fd, HDIO_GETGEO, &g)) {
+ ioctl_ok = 1;
+
+ heads = g.heads;
+ sectors = g.sectors;
+ cylinders = g.cylinders;
+ }
+
+ if (specified_heads)
+ heads = specified_heads;
+ if (specified_sectors)
+ sectors = specified_sectors;
+ if (specified_cylinders)
+ cylinders = specified_cylinders;
+
+ cylindersize = heads * sectors;
+
+ if (ioctl_ok) {
+ if (g.start && !force) {
+ warn(
+ "Warning: start=%d - this looks like a partition rather than\n"
+ "the entire disk. Using fdisk on it is probably meaningless.\n"
+ "[Use the --force option if you really want this]\n", g.start);
+ exit(1);
+ }
+ if (heads != g.heads)
+ warn("Warning: HDIO_GETGEO says that there are %d heads\n",
+ g.heads);
+ if (sectors != g.sectors)
+ warn("Warning: HDIO_GETGEO says that there are %d sectors\n",
+ g.sectors);
+ if (cylinders != g.cylinders)
+ warn("Warning: HDIO_GETGEO says that there are %d cylinders\n",
+ g.cylinders);
+ } else if (!silent)
+ if (!heads || !sectors || !cylinders)
+ printf("Disk %s: cannot get geometry\n", dev);
+ if (sectors > 63)
+ warn("Warning: unlikely number of sectors (%d) - usually at most 63\n"
+ "This will give problems with all software that uses C/H/S addressing.\n",
+ sectors);
+ if (!silent)
+ printf("\nDisk %s: %lu heads, %lu sectors, %lu cylinders\n",
+ dev, heads, sectors, cylinders);
+}
+
+typedef struct { unsigned char h,s,c; } chs; /* has some c bits in s */
+chs zero_chs = { 0,0,0 };
+
+typedef struct { unsigned long h,s,c; } longchs;
+longchs zero_longchs;
+
+chs
+longchs_to_chs (longchs aa) {
+ chs a;
+
+ if (aa.h < 256 && aa.s < 64 && aa.c < 1024) {
+ a.h = aa.h;
+ a.s = aa.s | ((aa.c >> 2) & 0xc0);
+ a.c = (aa.c & 0xff);
+ } else if (heads && sectors) {
+ a.h = heads - 1;
+ a.s = sectors | 0xc0;
+ a.c = 0xff;
+ } else
+ a = zero_chs;
+ return a;
+}
+
+longchs
+chs_to_longchs (chs a) {
+ longchs aa;
+
+ aa.h = a.h;
+ aa.s = (a.s & 0x3f);
+ aa.c = (a.s & 0xc0);
+ aa.c = (aa.c << 2) + a.c;
+ return aa;
+}
+
+longchs
+ulong_to_longchs (unsigned long sno) {
+ longchs aa;
+
+ if (heads && sectors && cylindersize) {
+ aa.s = 1 + sno % sectors;
+ aa.h = (sno / sectors) % heads;
+ aa.c = sno / cylindersize;
+ return aa;
+ } else {
+ return zero_longchs;
+ }
+}
+
+unsigned long
+longchs_to_ulong (longchs aa) {
+ return (aa.c*cylindersize + aa.h*sectors + aa.s - 1);
+}
+
+chs
+ulong_to_chs (unsigned long sno) {
+ return longchs_to_chs(ulong_to_longchs(sno));
+}
+
+unsigned long
+chs_to_ulong (chs a) {
+ return longchs_to_ulong(chs_to_longchs(a));
+}
+
+int
+is_equal_chs (chs a, chs b) {
+ return (a.h == b.h && a.s == b.s && a.c == b.c);
+}
+
+int
+chs_ok (chs a, char *v, char *w) {
+ longchs aa = chs_to_longchs(a);
+ int ret = 1;
+
+ if (is_equal_chs(a, zero_chs))
+ return 1;
+ if (heads && aa.h >= heads) {
+ warn("%s of partition %s has impossible value for head: "
+ "%d (should be in 0-%d)\n", w, v, aa.h, heads-1);
+ ret = 0;
+ }
+ if (sectors && (aa.s == 0 || aa.s > sectors)) {
+ warn("%s of partition %s has impossible value for sector: "
+ "%d (should be in 1-%d)\n", w, v, aa.s, sectors);
+ ret = 0;
+ }
+ if (cylinders && aa.c >= cylinders) {
+ warn("%s of partition %s has impossible value for cylinders: "
+ "%d (should be in 0-%d)\n", w, v, aa.c, cylinders-1);
+ ret = 0;
+ }
+ return ret;
+}
+
+/*
+ * D. About system Ids
+ */
+
+#define EMPTY_PARTITION 0
+#define EXTENDED_PARTITION 5
+#define WIN98_EXTENDED 0x0f
+#define DM6_AUX1PARTITION 0x51
+#define DM6_AUX3PARTITION 0x53
+#define DM6_PARTITION 0x54
+#define EZD_PARTITION 0x55
+#define LINUX_SWAP 0x82
+#define LINUX_NATIVE 0x83
+#define LINUX_EXTENDED 0x85
+#define BSD_PARTITION 0xa5
+
+/*
+ * List of system Id's, adapted from fdisk 2.0d and <linux/genhd.h>
+ * and SFS and several other sources.
+ */
+struct systypes {
+ unsigned char type;
+ char *name;
+} sys_types[] = {
+ {0, "Empty"},
+ {1, "DOS 12-bit FAT"}, /* Primary DOS with 12-bit FAT */
+ {2, "XENIX /"}, /* XENIX / filesystem */
+ {3, "XENIX /usr"}, /* XENIX /usr filesystem */
+ {4, "DOS 16-bit FAT <32M"}, /* Primary DOS with 16-bit FAT */
+ {5, "DOS Extended"}, /* DOS 3.3+ extended partition */
+ {6, "DOS 16-bit FAT >=32M"},
+ {7, "HPFS / NTFS"},
+ {8, "AIX boot or SplitDrive"},
+ {9, "AIX data or Coherent"},
+ {0x0a, "OS/2 Boot Manager"},
+ {0x0b, "Win95 FAT32"},
+ {0x0c, "Win95 FAT32 (LBA)"},
+ {0x0e, "Win95 FAT16 (LBA)"},
+ {0x0f, "Win95 Extended (LBA)"},
+ {0x10, "OPUS"},
+ {0x11, "Hidden DOS FAT12"},
+ {0x12, "Compaq diagnostics"},
+ {0x14, "Hidden DOS FAT16"},
+ {0x16, "Hidden DOS FAT16 (big)"},
+ {0x17, "Hidden HPFS/NTFS"},
+ {0x18, "AST Windows swapfile"},
+ {0x24, "NEC DOS"},
+ {0x3c, "PartitionMagic recovery"},
+ {0x40, "Venix 80286"},
+ {0x41, "Linux/MINIX (sharing disk with DRDOS)"},
+ {0x42, "SFS or Linux swap (sharing disk with DRDOS)"},
+ {0x43, "Linux native (sharing disk with DRDOS)"},
+ {0x50, "DM (disk manager)"},
+ {0x51, "DM6 Aux1 (or Novell)"},
+ {0x52, "CP/M or Microport SysV/AT"},
+ {0x53, "DM6 Aux3"},
+ {0x54, "DM6"},
+ {0x55, "EZ-Drive (disk manager)"},
+ {0x56, "Golden Bow (disk manager)"},
+ {0x5c, "Priam Edisk (disk manager)"},
+ {0x61, "SpeedStor"},
+ {0x63, "GNU HURD or Mach or Sys V/386 (such as ISC UNIX)"},
+ {0x64, "Novell Netware 286"},
+ {0x65, "Novell Netware 386"},
+ {0x70, "DiskSecure Multi-Boot"},
+ {0x75, "PC/IX"},
+ {0x77, "QNX4.x"},
+ {0x78, "QNX4.x 2nd part"},
+ {0x79, "QNX4.x 3rd part"},
+ {0x80, "MINIX until 1.4a"},
+ {0x81, "MINIX / old Linux"},
+ {0x82, "Linux swap"},
+ {0x83, "Linux native"},
+ {0x84, "OS/2 hidden C: drive"},
+ {0x85, "Linux extended"},
+ {0x86, "NTFS volume set"},
+ {0x87, "NTFS volume set"},
+ {0x93, "Amoeba"},
+ {0x94, "Amoeba BBT"}, /* (bad block table) */
+ {0xa0, "IBM Thinkpad hibernation"}, /* according to dan@fch.wimsey.bc.ca */
+ {0xa5, "BSD/386"}, /* 386BSD */
+ {0xa6, "OpenBSD"},
+ {0xa7, "NeXTSTEP 486"},
+ {0xb7, "BSDI fs"},
+ {0xb8, "BSDI swap"},
+ {0xc1, "DRDOS/sec (FAT-12)"},
+ {0xc4, "DRDOS/sec (FAT-16, < 32M)"},
+ {0xc6, "DRDOS/sec (FAT-16, >= 32M)"},
+ {0xc7, "Syrinx"},
+ {0xdb, "CP/M or Concurrent CP/M or Concurrent DOS or CTOS"},
+ {0xe1, "DOS access or SpeedStor 12-bit FAT extended partition"},
+ {0xe3, "DOS R/O or SpeedStor"},
+ {0xe4, "SpeedStor 16-bit FAT extended partition < 1024 cyl."},
+ {0xeb, "BeOS fs"},
+ {0xf1, "SpeedStor"},
+ {0xf2, "DOS 3.3+ secondary"},
+ {0xf4, "SpeedStor large partition"},
+ {0xfe, "SpeedStor >1024 cyl. or LANstep"},
+ {0xff, "Xenix Bad Block Table"}
+};
+
+
+const char *
+sysname(unsigned char type) {
+ struct systypes *s;
+
+ for (s = sys_types; s - sys_types < SIZE(sys_types); s++)
+ if (s->type == type)
+ return s->name;
+ return "Unknown";
+}
+
+void
+list_types(void) {
+ struct systypes *s;
+
+ printf("Id Name\n\n");
+ for (s = sys_types; s - sys_types < SIZE(sys_types); s++)
+ printf("%2x %s\n", s->type, s->name);
+}
+
+int
+is_extended(unsigned char type) {
+ return (type == EXTENDED_PARTITION
+ || type == LINUX_EXTENDED
+ || type == WIN98_EXTENDED);
+}
+
+int
+is_bsd(unsigned char type) {
+ return (type == BSD_PARTITION);
+}
+
+/*
+ * E. About partitions
+ */
+
+/* MS/DOS partition */
+
+struct partition {
+ unsigned char bootable; /* 0 or 0x80 */
+ chs begin_chs;
+ unsigned char sys_type;
+ chs end_chs;
+ unsigned int start_sect; /* starting sector counting from 0 */
+ unsigned int nr_sects; /* nr of sectors in partition */
+};
+
+/* Unfortunately, partitions are not aligned, and non-Intel machines
+ are unhappy with non-aligned integers. So, we need a copy by hand. */
+int
+copy_to_int(unsigned char *cp) {
+ unsigned int m;
+
+ m = *cp++;
+ m += (*cp++ << 8);
+ m += (*cp++ << 16);
+ m += (*cp++ << 24);
+ return m;
+}
+
+void
+copy_from_int(int m, char *cp) {
+ *cp++ = (m & 0xff); m >>= 8;
+ *cp++ = (m & 0xff); m >>= 8;
+ *cp++ = (m & 0xff); m >>= 8;
+ *cp++ = (m & 0xff);
+}
+
+void
+copy_to_part(char *cp, struct partition *p) {
+ p->bootable = *cp++;
+ p->begin_chs.h = *cp++;
+ p->begin_chs.s = *cp++;
+ p->begin_chs.c = *cp++;
+ p->sys_type = *cp++;
+ p->end_chs.h = *cp++;
+ p->end_chs.s = *cp++;
+ p->end_chs.c = *cp++;
+ p->start_sect = copy_to_int(cp);
+ p->nr_sects = copy_to_int(cp+4);
+}
+
+void
+copy_from_part(struct partition *p, char *cp) {
+ *cp++ = p->bootable;
+ *cp++ = p->begin_chs.h;
+ *cp++ = p->begin_chs.s;
+ *cp++ = p->begin_chs.c;
+ *cp++ = p->sys_type;
+ *cp++ = p->end_chs.h;
+ *cp++ = p->end_chs.s;
+ *cp++ = p->end_chs.c;
+ copy_from_int(p->start_sect, cp);
+ copy_from_int(p->nr_sects, cp+4);
+}
+
+/* Roughly speaking, Linux doesn't use any of the above fields except
+ for partition type, start sector and number of sectors. (However,
+ see also linux/drivers/scsi/fdomain.c.)
+ The only way partition type is used (in the kernel) is the comparison
+ for equality with EXTENDED_PARTITION (and these Disk Manager types). */
+
+struct part_desc {
+ unsigned long start;
+ unsigned long size;
+ unsigned long sector, offset; /* disk location of this info */
+ struct partition p;
+ struct part_desc *ep; /* extended partition containing this one */
+ int ptype;
+#define DOS_TYPE 0
+#define BSD_TYPE 1
+} zero_part_desc;
+
+struct part_desc *
+outer_extended_partition(struct part_desc *p) {
+ while (p->ep)
+ p = p->ep;
+ return p;
+}
+
+int
+is_parent(struct part_desc *pp, struct part_desc *p) {
+ while (p) {
+ if (pp == p)
+ return 1;
+ p = p->ep;
+ }
+ return 0;
+}
+
+struct disk_desc {
+ struct part_desc partitions[128];
+ int partno;
+} oldp, newp;
+
+/* determine where on the disk this information goes */
+void
+add_sector_and_offset(struct disk_desc *z) {
+ int pno;
+ struct part_desc *p;
+
+ for (pno = 0; pno < z->partno; pno++) {
+ p = &(z->partitions[pno]);
+ p->offset = 0x1be + (pno%4)*sizeof(struct partition);
+ p->sector = (p->ep ? p->ep->start : 0);
+ }
+}
+
+/* tell the kernel to reread the partition tables */
+int reread_ioctl(int fd) {
+ if(ioctl(fd, BLKRRPART)) {
+ perror("BLKRRPART");
+ return -1;
+ }
+ return 0;
+}
+
+/* reread after writing */
+void
+reread_disk_partition(char *dev, int fd) {
+ printf("Re-reading the partition table ...\n");
+ fflush(stdout);
+ sync();
+ sleep(3); /* superfluous since 1.3.20 */
+
+ if(reread_ioctl(fd))
+ printf("The command to re-read the partition table failed\n"
+ "Reboot your system now, before using mkfs\n");
+
+ if (close(fd)) {
+ perror(dev);
+ printf("Error closing %s\n", dev);
+ }
+ printf("\n");
+}
+
+/* find Linux name of this partition, assuming that it will have a name */
+int
+index_to_linux(int pno, struct disk_desc *z) {
+ int i, ct = 1;
+ struct part_desc *p = &(z->partitions[0]);
+ for (i=0; i<pno; i++,p++)
+ if(i < 4 || (p->size > 0 && !is_extended(p->p.sys_type)))
+ ct++;
+ return ct;
+}
+
+int
+linux_to_index(int lpno, struct disk_desc *z) {
+ int i, ct = 0;
+ struct part_desc *p = &(z->partitions[0]);
+ for (i=0; i<z->partno && ct < lpno; i++,p++)
+ if((i < 4 || (p->size > 0 && !is_extended(p->p.sys_type)))
+ && ++ct == lpno)
+ return i;
+ return -1;
+}
+
+int
+asc_to_index(char *pnam, struct disk_desc *z) {
+ int pnum, pno;
+
+ if (*pnam == '#') {
+ pno = atoi(pnam+1);
+ } else {
+ pnum = atoi(pnam);
+ pno = linux_to_index(pnum, z);
+ }
+ if (!(pno >= 0 && pno < z->partno))
+ fatal("%s: no such partition\n", pnam);
+ return pno;
+}
+
+/*
+ * List partitions - in terms of sectors, blocks or cylinders
+ */
+#define F_SECTOR 1
+#define F_BLOCK 2
+#define F_CYLINDER 3
+#define F_MEGABYTE 4
+
+int default_format = F_MEGABYTE;
+int specified_format = 0;
+int show_extended = 0;
+int one_only = 0;
+int one_only_pno;
+int increment = 0;
+
+void
+set_format(char c) {
+ switch(c) {
+ default:
+ printf("unrecognized format - using sectors\n");
+ case 'S': specified_format = F_SECTOR; break;
+ case 'B': specified_format = F_BLOCK; break;
+ case 'C': specified_format = F_CYLINDER; break;
+ case 'M': specified_format = F_MEGABYTE; break;
+ }
+}
+
+unsigned long
+unitsize(int format) {
+ default_format = (cylindersize ? F_CYLINDER : F_MEGABYTE);
+ if (!format && !(format = specified_format))
+ format = default_format;
+
+ switch(format) {
+ default:
+ case F_CYLINDER:
+ if(cylindersize) return cylindersize;
+ case F_SECTOR:
+ return 1;
+ case F_BLOCK:
+ return 2;
+ case F_MEGABYTE:
+ return 2048;
+ }
+}
+
+unsigned long
+get_disksize(int format) {
+ unsigned long cs = cylinders;
+ if (cs && leave_last)
+ cs--;
+ return (cs * cylindersize) / unitsize(format);
+}
+
+void
+out_partition_header(char *dev, int format) {
+ if (dump) {
+ printf("# partition table of %s\n", dev);
+ printf("unit: sectors\n\n");
+ return;
+ }
+
+ default_format = (cylindersize ? F_CYLINDER : F_MEGABYTE);
+ if (!format && !(format = specified_format))
+ format = default_format;
+
+ switch(format) {
+ default:
+ printf("unimplemented format - using %s\n",
+ cylindersize ? "cylinders" : "sectors");
+ case F_CYLINDER:
+ if (cylindersize) {
+ printf("Units = cylinders of %lu bytes, blocks of 1024 bytes"
+ ", counting from %d\n\n",
+ cylindersize<<9, increment);
+ printf(" Device Boot Start End #cyls #blocks Id System\n");
+ break;
+ }
+ /* fall through */
+ case F_SECTOR:
+ printf("Units = sectors of 512 bytes, counting from %d\n\n",
+ increment);
+ printf(" Device Boot Start End #sectors Id System\n");
+ break;
+ case F_BLOCK:
+ printf("Units = blocks of 1024 bytes, counting from %d\n\n",
+ increment);
+ printf(" Device Boot Start End #blocks Id System\n");
+ break;
+ case F_MEGABYTE:
+ printf("Units = megabytes of 1048576 bytes, blocks of 1024 bytes"
+ ", counting from %d\n\n", increment);
+ printf(" Device Boot Start End MB #blocks Id System\n");
+ break;
+ }
+}
+
+static void
+out_rounddown(int width, unsigned long n, unsigned long unit, int inc) {
+ printf("%*lu", width, inc + n/unit);
+ if (unit != 1)
+ putchar((n % unit) ? '+' : ' ');
+ putchar(' ');
+}
+
+static void
+out_roundup(int width, unsigned long n, unsigned long unit, int inc) {
+ if (n == (unsigned long)(-1))
+ printf("%*s", width, "-");
+ else
+ printf("%*lu", width, inc + n/unit);
+ if (unit != 1)
+ putchar(((n+1) % unit) ? '-' : ' ');
+ putchar(' ');
+}
+
+static void
+out_roundup_size(int width, unsigned long n, unsigned long unit) {
+ printf("%*lu", width, (n+unit-1)/unit);
+ if (unit != 1)
+ putchar((n % unit) ? '-' : ' ');
+ putchar(' ');
+}
+
+void
+out_partition(char *dev, int format, struct part_desc *p, struct disk_desc *z) {
+ unsigned long start, end, size;
+ int pno, lpno;
+
+ if (!format && !(format = specified_format))
+ format = default_format;
+
+ pno = p - &(z->partitions[0]); /* our index */
+ lpno = index_to_linux(pno, z); /* name of next one that has a name */
+ if(pno == linux_to_index(lpno, z)) /* was that us? */
+ printf("%8s%-2u", dev, lpno); /* yes */
+ else if(show_extended)
+ printf(" - ");
+ else
+ return;
+ putchar(dump ? ':' : ' ');
+
+ start = p->start;
+ end = p->start + p->size - 1;
+ size = p->size;
+
+ if (dump) {
+ printf(" start=%9lu", start);
+ printf(", size=%8lu", size);
+ if (p->ptype == DOS_TYPE) {
+ printf(", Id=%2x", p->p.sys_type);
+ if (p->p.bootable == 0x80)
+ printf(", bootable");
+ }
+ printf("\n");
+ return;
+ }
+
+ if(p->ptype != DOS_TYPE || p->p.bootable == 0)
+ printf(" ");
+ else if(p->p.bootable == 0x80)
+ printf(" * ");
+ else
+ printf(" ? "); /* garbage */
+
+ switch(format) {
+ case F_CYLINDER:
+ if (cylindersize) {
+ out_rounddown(6, start, cylindersize, increment);
+ out_roundup(6, end, cylindersize, increment);
+ out_roundup_size(6, size, cylindersize);
+ out_rounddown(8, size, 2, 0);
+ break;
+ }
+ /* fall through */
+ default:
+ case F_SECTOR:
+ out_rounddown(9, start, 1, increment);
+ out_roundup(9, end, 1, increment);
+ out_rounddown(9, size, 1, 0);
+ break;
+ case F_BLOCK:
+#if 0
+ printf("%8lu,%3lu ",
+ p->sector/2, ((p->sector & 1) ? 512 : 0) + p->offset);
+#endif
+ out_rounddown(8, start, 2, increment);
+ out_roundup(8, end, 2, increment);
+ out_rounddown(8, size, 2, 0);
+ break;
+ case F_MEGABYTE:
+ out_rounddown(5, start, 2048, increment);
+ out_roundup(5, end, 2048, increment);
+ out_roundup_size(5, size, 2048);
+ out_rounddown(8, size, 2, 0);
+ break;
+ }
+ if (p->ptype == DOS_TYPE) {
+ printf(" %2x %s\n",
+ p->p.sys_type, sysname(p->p.sys_type));
+ } else {
+ printf("\n");
+ }
+
+ /* Is chs as we expect? */
+ if (!quiet && p->ptype == DOS_TYPE) {
+ chs a, b;
+ longchs aa, bb;
+ a = (size ? ulong_to_chs(start) : zero_chs);
+ b = p->p.begin_chs;
+ aa = chs_to_longchs(a);
+ bb = chs_to_longchs(b);
+ if(a.s && !is_equal_chs(a, b))
+ printf("\t\tstart: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n",
+ aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
+ a = (size ? ulong_to_chs(end) : zero_chs);
+ b = p->p.end_chs;
+ aa = chs_to_longchs(a);
+ bb = chs_to_longchs(b);
+ if(a.s && !is_equal_chs(a, b))
+ printf("\t\tend: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n",
+ aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
+ if(cylinders && cylinders < 1024 && bb.c > cylinders)
+ printf("partition ends on cylinder %ld, beyond the end of the disk\n",
+ bb.c);
+ }
+}
+
+void
+out_partitions(char *dev, struct disk_desc *z) {
+ int pno, format = 0;
+
+ if (z->partno == 0)
+ printf("No partitions found\n");
+ else {
+ out_partition_header(dev, format);
+ for(pno=0; pno < z->partno; pno++) {
+ out_partition(dev, format, &(z->partitions[pno]), z);
+ if(show_extended && pno%4==3)
+ printf("\n");
+ }
+ }
+}
+
+static int
+disj(struct part_desc *p, struct part_desc *q) {
+ return
+ ((p->start + p->size <= q->start)
+ || (is_extended(p->p.sys_type)
+ && q->start + q->size <= p->start + p->size));
+}
+
+char *
+pnumber(struct part_desc *p, struct disk_desc *z) {
+ static char buf[20];
+ int this, next;
+ struct part_desc *p0 = &(z->partitions[0]);
+
+ this = index_to_linux(p-p0, z);
+ next = index_to_linux(p-p0+1, z);
+
+ if (next > this)
+ sprintf(buf, "%d", this);
+ else
+ sprintf(buf, "[%d]", this);
+ return buf;
+}
+
+int
+partitions_ok(struct disk_desc *z) {
+ struct part_desc *partitions = &(z->partitions[0]), *p, *q;
+ int partno = z->partno;
+
+#define PNO(p) pnumber(p, z)
+
+ /* Have at least 4 partitions been defined? */
+ if (partno < 4) {
+ if (!partno)
+ fatal("no partition table present.\n");
+ else
+ fatal("strange, only %d partitions defined.\n", partno);
+ return 0;
+ }
+
+ /* Are the partitions of size 0 marked empty?
+ And do they have start = 0? And bootable = 0? */
+ for (p = partitions; p - partitions < partno; p++)
+ if (p->size == 0) {
+ if(p->p.sys_type != EMPTY_PARTITION)
+ warn("Warning: partition %s has size 0 but is not marked Empty\n",
+ PNO(p));
+ else if(p->p.bootable != 0)
+ warn("Warning: partition %s has size 0 and is bootable\n",
+ PNO(p));
+ else if(p->p.start_sect != 0)
+ warn("Warning: partition %s has size 0 and nonzero start\n",
+ PNO(p));
+ /* all this is probably harmless, no error return */
+ }
+
+ /* Are the logical partitions contained in their extended partitions? */
+ for (p = partitions+4; p < partitions+partno; p++)
+ if (p->ptype == DOS_TYPE)
+ if (p->size && !is_extended(p->p.sys_type)) {
+ q = p->ep;
+ if (p->start < q->start || p->start + p->size > q->start + q->size) {
+ warn("Warning: partition %s ", PNO(p));
+ warn("is not contained in partition %s\n", PNO(q));
+ return 0;
+ }
+ }
+
+ /* Are the data partitions mutually disjoint? */
+ for (p = partitions; p < partitions+partno; p++)
+ if (p->size && !is_extended(p->p.sys_type))
+ for (q = p+1; q < partitions+partno; q++)
+ if (q->size && !is_extended(q->p.sys_type))
+ if(!((p->start > q-> start) ? disj(q,p) : disj(p,q))) {
+ warn("Warning: partitions %s ", PNO(p));
+ warn("and %s overlap\n", PNO(q));
+ return 0;
+ }
+
+ /* Are the data partitions and the extended partition
+ table sectors disjoint? */
+ for (p = partitions; p < partitions+partno; p++)
+ if (p->size && !is_extended(p->p.sys_type))
+ for (q = partitions; q < partitions+partno; q++)
+ if (is_extended(q->p.sys_type))
+ if (p->start <= q->start && p->start + p->size > q->start) {
+ warn("Warning: partition %s contains part of ", PNO(p));
+ warn("the partition table (sector %lu),\n", q->start);
+ warn("and will destroy it when filled\n");
+ return 0;
+ }
+
+ /* Do they start past zero and end before end-of-disk? */
+ { unsigned long ds = get_disksize(F_SECTOR);
+ for (p = partitions; p < partitions+partno; p++)
+ if (p->size) {
+ if(p->start == 0) {
+ warn("Warning: partition %s starts at sector 0\n", PNO(p));
+ return 0;
+ }
+ if (p->size && p->start + p->size > ds) {
+ warn("Warning: partition %s extends past end of disk\n", PNO(p));
+ return 0;
+ }
+ }
+ }
+
+ /* At most one chain of DOS extended partitions ? */
+ /* It seems that the OS/2 fdisk has the additional requirement
+ that the extended partition must be the fourth one */
+ { int ect = 0;
+ for (p = partitions; p < partitions+4; p++)
+ if (p->p.sys_type == EXTENDED_PARTITION)
+ ect++;
+ if (ect > 1 && !Linux) {
+ warn("Among the primary partitions, at most one can be extended\n");
+ warn(" (although this is not a problem under Linux)\n");
+ return 0;
+ }
+ }
+
+ /*
+ * Do all partitions start at a cylinder boundary ?
+ * (this is not required for Linux)
+ * The first partition starts after MBR.
+ * Logical partitions start slightly after the containing extended partn.
+ */
+ if (cylindersize) {
+ for(p = partitions; p < partitions+partno; p++)
+ if (p->size) {
+ if(p->start % cylindersize != 0
+ && (!p->ep || p->start / cylindersize != p->ep->start / cylindersize)
+ && (p->p.start_sect >= cylindersize)) {
+ warn("Warning: partition %s does not start "
+ "at a cylinder boundary\n", PNO(p));
+ if (!Linux)
+ return 0;
+ }
+ if((p->start + p->size) % cylindersize) {
+ warn("Warning: partition %s does not end "
+ "at a cylinder boundary\n", PNO(p));
+ if (!Linux)
+ return 0;
+ }
+ }
+ }
+
+ /* Usually, one can boot only from primary partitions. */
+ /* In fact, from a unique one only. */
+ /* do not warn about bootable extended partitions -
+ often LILO is there */
+ { int pno = -1;
+ for(p = partitions; p < partitions+partno; p++)
+ if (p->p.bootable) {
+ if (pno == -1)
+ pno = p - partitions;
+ else if (p - partitions < 4) {
+ warn("Warning: more than one primary partition is marked "
+ "bootable (active)\n"
+ "This does not matter for LILO, but the DOS MBR will "
+ "not boot this disk.\n");
+ break;
+ }
+ if (p - partitions >= 4) {
+ warn("Warning: usually one can boot from primary partitions "
+ "only\n" "LILO disregards the `bootable' flag.\n");
+ break;
+ }
+ }
+ if (pno == -1 || pno >= 4)
+ warn("Warning: no primary partition is marked bootable (active)\n"
+ "This does not matter for LILO, but the DOS MBR will "
+ "not boot this disk.\n");
+ }
+
+ /* Is chs as we expect? */
+ for(p = partitions; p < partitions+partno; p++)
+ if(p->ptype == DOS_TYPE) {
+ chs a, b;
+ longchs aa, bb;
+ a = p->size ? ulong_to_chs(p->start) : zero_chs;
+ b = p->p.begin_chs;
+ aa = chs_to_longchs(a);
+ bb = chs_to_longchs(b);
+ if (!chs_ok(b, PNO(p), "start"))
+ return 0;
+ if(a.s && !is_equal_chs(a, b))
+ warn("partition %s: start: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n",
+ PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
+ a = p->size ? ulong_to_chs(p->start + p->size - 1) : zero_chs;
+ b = p->p.end_chs;
+ aa = chs_to_longchs(a);
+ bb = chs_to_longchs(b);
+ if (!chs_ok(b, PNO(p), "end"))
+ return 0;
+ if(a.s && !is_equal_chs(a, b))
+ warn("partition %s: end: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n",
+ PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
+ if(cylinders && cylinders < 1024 && bb.c > cylinders)
+ warn("partition %s ends on cylinder %ld, beyond the end of the disk\n",
+ PNO(p), bb.c);
+ }
+
+ return 1;
+
+#undef PNO
+}
+
+static void
+extended_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) {
+ char *cp;
+ struct sector *s;
+ unsigned long start, here, next;
+ int i, moretodo = 1;
+ struct partition p;
+ struct part_desc *partitions = &(z->partitions[0]);
+ int pno = z->partno;
+
+ here = start = ep->start;
+
+ while (moretodo) {
+ moretodo = 0;
+
+ if (!(s = get_sector(dev, fd, here)))
+ break;
+
+ if (!msdos_signature(s))
+ break;
+
+ cp = s->data + 0x1be;
+
+ if (pno+4 >= SIZE(z->partitions)) {
+ printf("too many partitions - ignoring those past nr (%d)\n",
+ pno-1);
+ break;
+ }
+
+ next = 0;
+
+ for (i=0; i<4; i++,cp += sizeof(struct partition)) {
+ partitions[pno].sector = here;
+ partitions[pno].offset = cp - s->data;
+ partitions[pno].ep = ep;
+ copy_to_part(cp,&p);
+ if (is_extended(p.sys_type)) {
+ if (next)
+ printf("tree of partitions?\n");
+ partitions[pno].start = next = start + p.start_sect;
+ moretodo = 1;
+ } else {
+ partitions[pno].start = here + p.start_sect;
+ }
+ partitions[pno].size = p.nr_sects;
+ partitions[pno].ptype = DOS_TYPE;
+ partitions[pno].p = p;
+ pno++;
+ }
+ here = next;
+ }
+
+ z->partno = pno;
+}
+
+#define BSD_DISKMAGIC (0x82564557UL)
+#define BSD_MAXPARTITIONS 8
+#define BSD_FS_UNUSED 0
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+struct bsd_disklabel {
+ u32 d_magic;
+ char d_junk1[4];
+ char d_typename[16];
+ char d_packname[16];
+ char d_junk2[92];
+ u32 d_magic2;
+ char d_junk3[2];
+ u16 d_npartitions; /* number of partitions in following */
+ char d_junk4[8];
+ struct bsd_partition { /* the partition table */
+ u32 p_size; /* number of sectors in partition */
+ u32 p_offset; /* starting sector */
+ u32 p_fsize; /* filesystem basic fragment size */
+ u8 p_fstype; /* filesystem type, see below */
+ u8 p_frag; /* filesystem fragments per block */
+ u16 p_cpg; /* filesystem cylinders per group */
+ } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
+};
+
+static void
+bsd_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) {
+ struct bsd_disklabel *l;
+ struct bsd_partition *bp, *bp0;
+ unsigned long start = ep->start;
+ struct sector *s;
+ struct part_desc *partitions = &(z->partitions[0]);
+ int pno = z->partno;
+
+ if (!(s = get_sector(dev,fd,start+1)))
+ return;
+ l = (struct bsd_disklabel *) (s->data);
+ if (l->d_magic != BSD_DISKMAGIC)
+ return;
+
+ bp = bp0 = &l->d_partitions[0];
+ while (bp - bp0 <= BSD_MAXPARTITIONS) {
+ if (pno+1 >= SIZE(z->partitions)) {
+ printf("too many partitions - ignoring those "
+ "past nr (%d)\n", pno-1);
+ break;
+ }
+ if (bp->p_fstype != BSD_FS_UNUSED) {
+ partitions[pno].start = bp->p_offset;
+ partitions[pno].size = bp->p_size;
+ partitions[pno].sector = start+1;
+ partitions[pno].offset = (char *)bp - (char *)bp0;
+ partitions[pno].ep = 0;
+ partitions[pno].ptype = BSD_TYPE;
+ pno++;
+ }
+ bp++;
+ }
+ z->partno = pno;
+}
+
+static int
+msdos_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) {
+ int i;
+ char *cp;
+ struct partition pt;
+ struct sector *s;
+ struct part_desc *partitions = &(z->partitions[0]);
+ int pno = z->partno;
+
+ if (!(s = get_sector(dev, fd, start)))
+ return 0;
+
+ if (!msdos_signature(s))
+ return 0;
+
+ cp = s->data + 0x1be;
+ copy_to_part(cp,&pt);
+
+ /* If I am not mistaken, recent kernels will hide this from us,
+ so we will never actually see traces of a Disk Manager */
+ if (pt.sys_type == DM6_PARTITION
+ || pt.sys_type == EZD_PARTITION
+ || pt.sys_type == DM6_AUX1PARTITION
+ || pt.sys_type == DM6_AUX3PARTITION) {
+ printf("detected Disk Manager - unable to handle that\n");
+ return 0;
+ }
+ { unsigned int sig = *(unsigned short *)(s->data + 2);
+ if (sig <= 0x1ae
+ && *(unsigned short *)(s->data + sig) == 0x55aa
+ && (1 & *(unsigned char *)(s->data + sig + 2))) {
+ printf("DM6 signature found - giving up\n");
+ return 0;
+ }
+ }
+
+ for (pno=0; pno<4; pno++,cp += sizeof(struct partition)) {
+ partitions[pno].sector = start;
+ partitions[pno].offset = cp - s->data;
+ copy_to_part(cp,&pt);
+ partitions[pno].start = start + pt.start_sect;
+ partitions[pno].size = pt.nr_sects;
+ partitions[pno].ep = 0;
+ partitions[pno].p = pt;
+ }
+
+ z->partno = pno;
+
+ for (i=0; i<4; i++) {
+ if (is_extended(partitions[i].p.sys_type)) {
+ if (!partitions[i].size) {
+ printf("strange..., an extended partition of size 0?\n");
+ continue;
+ }
+ extended_partition(dev, fd, &partitions[i], z);
+ }
+ if (is_bsd(partitions[i].p.sys_type)) {
+ if (!partitions[i].size) {
+ printf("strange..., a BSD partition of size 0?\n");
+ continue;
+ }
+ bsd_partition(dev, fd, &partitions[i], z);
+ }
+ }
+ return 1;
+}
+
+static int
+osf_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) {
+ return 0;
+}
+
+static int
+sun_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) {
+ return 0;
+}
+
+static int
+amiga_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) {
+ return 0;
+}
+
+void
+get_partitions(char *dev, int fd, struct disk_desc *z) {
+ z->partno = 0;
+
+ if (!msdos_partition(dev, fd, 0, z)
+ && !osf_partition(dev, fd, 0, z)
+ && !sun_partition(dev, fd, 0, z)
+ && !amiga_partition(dev, fd, 0, z)) {
+ printf(" %s: unrecognized partition\n", dev);
+ return;
+ }
+}
+
+int
+write_partitions(char *dev, int fd, struct disk_desc *z) {
+ struct sector *s;
+ struct part_desc *partitions = &(z->partitions[0]), *p;
+ int pno = z->partno;
+
+ if (no_write) {
+ printf("-n flag was given: Nothing changed\n");
+ exit(0);
+ }
+
+ for (p = partitions; p < partitions+pno; p++) {
+ s = get_sector(dev, fd, p->sector);
+ if (!s) return 0;
+ s->to_be_written = 1;
+ copy_from_part(&(p->p), s->data + p->offset);
+ *(unsigned short *)(&(s->data[0x1fe])) = 0xaa55;
+ }
+ if (save_sector_file) {
+ if (!save_sectors(dev, fd)) {
+ fatal("Failed saving the old sectors - aborting\n");
+ return 0;
+ }
+ }
+ if (!write_sectors(dev, fd)) {
+ error("Failed writing the partition on %s\n", dev);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * F. The standard input
+ */
+
+/*
+ * Input format:
+ * <start> <size> <type> <bootable> <c,h,s> <c,h,s>
+ * Fields are separated by whitespace or comma or semicolon possibly
+ * followed by whitespace; initial and trailing whitespace is ignored.
+ * Numbers can be octal, decimal or hexadecimal, decimal is default
+ * The <c,h,s> parts can (and probably should) be omitted.
+ * Bootable is specified as [*|-], with as default not-bootable.
+ * Type is given in hex, without the 0x prefix, or is [E|S|L|X], where
+ * L (LINUX_NATIVE (83)) is the default, S is LINUX_SWAP (82), and E
+ * is EXTENDED_PARTITION (5), X is LINUX_EXTENDED (85).
+ * The default value of start is the first nonassigned sector/cylinder/...
+ * The default value of size is as much as possible (until next
+ * partition or end-of-disk).
+ * .: end of chain of extended partitions.
+ *
+ * On interactive input an empty line means: all defaults.
+ * Otherwise empty lines are ignored.
+ */
+
+int eof, eob;
+
+struct dumpfld {
+ int fldno;
+ char *fldname;
+ int is_bool;
+} dumpflds[] = {
+ { 0, "start", 0 },
+ { 1, "size", 0 },
+ { 2, "Id", 0 },
+ { 3, "bootable", 1 },
+ { 4, "bh", 0 },
+ { 5, "bs", 0 },
+ { 6, "bc", 0 },
+ { 7, "eh", 0 },
+ { 8, "es", 0 },
+ { 9, "ec", 0 }
+};
+
+/*
+ * Read a line, split it into fields
+ *
+ * (some primitive handwork, but a more elaborate parser seems
+ * unnecessary)
+ */
+#define RD_EOF (-1)
+#define RD_CMD (-2)
+
+int
+read_stdin(unsigned char **fields, unsigned char *line, int fieldssize, int linesize) {
+ unsigned char *lp, *ip;
+ int c, fno;
+
+ /* boolean true and empty string at start */
+ line[0] = '*';
+ line[1] = 0;
+ for (fno=0; fno < fieldssize; fno++)
+ fields[fno] = line + 1;
+ fno = 0;
+
+ /* read a line from stdin */
+ lp = fgets(line+2, linesize, stdin);
+ if (lp == NULL) {
+ eof = 1;
+ return RD_EOF;
+ }
+ if (!(lp = index(lp, '\n')))
+ fatal("long or incomplete input line - quitting\n");
+ *lp = 0;
+
+ /* remove comments, if any */
+ if ((lp = index(line+2, '#')) != 0)
+ *lp = 0;
+
+ /* recognize a few commands - to be expanded */
+ if (!strcmp(line+2, "unit: sectors")) {
+ specified_format = F_SECTOR;
+ return RD_CMD;
+ }
+
+ /* dump style? - then bad input is fatal */
+ if ((ip = index(line+2, ':')) != 0) {
+ struct dumpfld *d;
+
+ nxtfld:
+ ip++;
+ while(isspace(*ip))
+ ip++;
+ if (*ip == 0)
+ return fno;
+ for(d = dumpflds; d-dumpflds < SIZE(dumpflds); d++) {
+ if(!strncmp(ip, d->fldname, strlen(d->fldname))) {
+ ip += strlen(d->fldname);
+ while(isspace(*ip))
+ ip++;
+ if (d->is_bool)
+ fields[d->fldno] = line;
+ else if (*ip == '=') {
+ while(isspace(*++ip)) ;
+ fields[d->fldno] = ip;
+ while(isalnum(*ip)) /* 0x07FF */
+ ip++;
+ } else
+ fatal("input error: `=' expected after %s field\n",
+ d->fldname);
+ if (fno <= d->fldno)
+ fno = d->fldno + 1;
+ if(*ip == 0)
+ return fno;
+ if(*ip != ',' && *ip != ';')
+ fatal("input error: unexpected character %c after %s field\n",
+ *ip, d->fldname);
+ *ip = 0;
+ goto nxtfld;
+ }
+ }
+ fatal("unrecognized input: %s\n", ip);
+ }
+
+ /* split line into fields */
+ lp = ip = line+2;
+ fields[fno++] = lp;
+ while((c = *ip++) != 0) {
+ if (!lp[-1] && (c == '\t' || c == ' '))
+ ;
+ else if (c == '\t' || c == ' ' || c == ',' || c == ';') {
+ *lp++ = 0;
+ if (fno < fieldssize)
+ fields[fno++] = lp;
+ continue;
+ } else
+ *lp++ = c;
+ }
+
+ if (lp == fields[fno-1])
+ fno--;
+ return fno;
+}
+
+/* read a number, use default if absent */
+int
+get_ul(char *u, unsigned long *up, unsigned long def, int base) {
+ char *nu;
+
+ if (*u) {
+ errno = 0;
+ *up = strtoul(u, &nu, base);
+ if (errno == ERANGE) {
+ printf("number too big\n");
+ return -1;
+ }
+ if (*nu) {
+ printf("trailing junk after number\n");
+ return -1;
+ }
+ } else
+ *up = def;
+ return 0;
+}
+
+/* There are two common ways to structure extended partitions:
+ as nested boxes, and as a chain. Sometimes the partitions
+ must be given in order. Sometimes all logical partitions
+ must lie inside the outermost extended partition.
+NESTED: every partition is contained in the surrounding partitions
+ and is disjoint from all others.
+CHAINED: every data partition is contained in the surrounding partitions
+ and disjoint from all others, but extended partitions may lie outside
+ (insofar as allowed by all_logicals_inside_outermost_extended).
+ONESECTOR: all data partitions are mutually disjoint; extended partitions
+ each use one sector only (except perhaps for the outermost one).
+*/
+int partitions_in_order = 0;
+int all_logicals_inside_outermost_extended = 1;
+enum { NESTED, CHAINED, ONESECTOR } boxes = NESTED;
+
+/* find the default value for <start> - assuming entire units */
+unsigned long
+first_free(int pno, int is_extended, struct part_desc *ep, int format,
+ unsigned long mid, struct disk_desc *z) {
+ unsigned long ff, fff;
+ unsigned long unit = unitsize(format);
+ struct part_desc *partitions = &(z->partitions[0]), *pp = 0;
+
+ /* if containing ep undefined, look at its container */
+ if (ep && ep->p.sys_type == EMPTY_PARTITION)
+ ep = ep->ep;
+
+ if (ep) {
+ if (boxes == NESTED || (boxes == CHAINED && !is_extended))
+ pp = ep;
+ else if (all_logicals_inside_outermost_extended)
+ pp = outer_extended_partition(ep);
+ }
+#if 0
+ ff = pp ? (pp->start + unit - 1) / unit : 0;
+#else
+ /* rounding up wastes almost an entire cylinder - round down
+ and leave it to compute_start_sect() to fix the difference */
+ ff = pp ? pp->start / unit : 0;
+#endif
+ /* MBR and 1st sector of an extended partition are never free */
+ if (unit == 1)
+ ff++;
+
+ again:
+ for(pp = partitions; pp < partitions+pno; pp++) {
+ if (!is_parent(pp, ep) && pp->size > 0) {
+ if ((partitions_in_order || pp->start / unit <= ff
+ || (mid && pp->start / unit <= mid))
+ && (fff = (pp->start + pp->size + unit - 1) / unit) > ff) {
+ ff = fff;
+ goto again;
+ }
+ }
+ }
+
+ return ff;
+}
+
+/* find the default value for <size> - assuming entire units */
+unsigned long
+max_length(int pno, int is_extended, struct part_desc *ep, int format,
+ unsigned long start, struct disk_desc *z) {
+ unsigned long fu;
+ unsigned long unit = unitsize(format);
+ struct part_desc *partitions = &(z->partitions[0]), *pp = 0;
+
+ /* if containing ep undefined, look at its container */
+ if (ep && ep->p.sys_type == EMPTY_PARTITION)
+ ep = ep->ep;
+
+ if (ep) {
+ if (boxes == NESTED || (boxes == CHAINED && !is_extended))
+ pp = ep;
+ else if (all_logicals_inside_outermost_extended)
+ pp = outer_extended_partition(ep);
+ }
+ fu = pp ? (pp->start + pp->size) / unit : get_disksize(format);
+
+ for(pp = partitions; pp < partitions+pno; pp++)
+ if (!is_parent(pp, ep) && pp->size > 0
+ && pp->start / unit >= start && pp->start / unit < fu)
+ fu = pp->start / unit;
+
+ return (fu > start) ? fu - start : 0;
+}
+
+/* compute starting sector of a partition inside an extended one */
+/* ep is 0 or points to surrounding extended partition */
+int
+compute_start_sect(struct part_desc *p, struct part_desc *ep) {
+ unsigned long base;
+ int inc = (DOS && sectors) ? sectors : 1;
+ int delta;
+
+ if (ep && p->start + p->size >= ep->start + 1)
+ delta = p->start - ep->start - inc;
+ else if (p->start == 0 && p->size > 0)
+ delta = -inc;
+ else
+ delta = 0;
+ if (delta < 0) {
+ p->start -= delta;
+ p->size += delta;
+ if (is_extended(p->p.sys_type) && boxes == ONESECTOR)
+ p->size = inc;
+ else if ((int)(p->size) <= 0) {
+ warn("no room for partition descriptor\n");
+ return 0;
+ }
+ }
+ base = (!ep ? 0
+ : (is_extended(p->p.sys_type) ?
+ outer_extended_partition(ep) : ep)->start);
+ p->ep = ep;
+ if (p->p.sys_type == EMPTY_PARTITION && p->size == 0) {
+ p->p.start_sect = 0;
+ p->p.begin_chs = zero_chs;
+ p->p.end_chs = zero_chs;
+ } else {
+ p->p.start_sect = p->start - base;
+ p->p.begin_chs = ulong_to_chs(p->start);
+ p->p.end_chs = ulong_to_chs(p->start + p->size - 1);
+ }
+ p->p.nr_sects = p->size;
+ return 1;
+}
+
+/* build the extended partition surrounding a given logical partition */
+int
+build_surrounding_extended(struct part_desc *p, struct part_desc *ep,
+ struct disk_desc *z) {
+ int inc = (DOS && sectors) ? sectors : 1;
+ int format = F_SECTOR;
+ struct part_desc *p0 = &(z->partitions[0]), *eep = ep->ep;
+
+ if (boxes == NESTED) {
+ ep->start = first_free(ep-p0, 1, eep, format, p->start, z);
+ ep->size = max_length(ep-p0, 1, eep, format, ep->start, z);
+ if (ep->start > p->start || ep->start + ep->size < p->start + p->size) {
+ warn("cannot build surrounding extended partition\n");
+ return 0;
+ }
+ } else {
+ ep->start = p->start;
+ if(boxes == CHAINED)
+ ep->size = p->size;
+ else
+ ep->size = inc;
+ }
+
+ ep->p.nr_sects = ep->size;
+ ep->p.bootable = 0;
+ ep->p.sys_type = EXTENDED_PARTITION;
+ if (!compute_start_sect(ep, eep) || !compute_start_sect(p, ep)) {
+ ep->p.sys_type = EMPTY_PARTITION;
+ ep->size = 0;
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+read_line(int pno, struct part_desc *ep, char *dev, int interactive,
+ struct disk_desc *z) {
+ unsigned char line[1000];
+ unsigned char *fields[11];
+ int fno, pct = pno%4;
+ struct part_desc p, *orig;
+ unsigned long ff, ff1, ul, ml, ml1, def;
+ int format, lpno, is_extd;
+
+ if (eof || eob)
+ return -1;
+
+ lpno = index_to_linux(pno, z);
+
+ if (interactive) {
+ if (pct == 0 && (show_extended || pno == 0))
+ warn("\n");
+ warn("%8s%d: ", dev, lpno);
+ }
+
+ /* read input line - skip blank lines when reading from a file */
+ do {
+ fno = read_stdin(fields, line, SIZE(fields), SIZE(line));
+ } while(fno == RD_CMD || (fno == 0 && !interactive));
+ if (fno == RD_EOF) {
+ return -1;
+ } else if (fno > 10 && *(fields[10]) != 0) {
+ printf("too many input fields\n");
+ return 0;
+ }
+
+ if (fno == 1 && !strcmp(fields[0], ".")) {
+ eob = 1;
+ return -1;
+ }
+
+ /* use specified format, but round to cylinders if F_MEGABYTE specified */
+ format = 0;
+ if (cylindersize && specified_format == F_MEGABYTE)
+ format = F_CYLINDER;
+
+ orig = (one_only ? &(oldp.partitions[pno]) : 0);
+
+ p = zero_part_desc;
+ p.ep = ep;
+
+ /* first read the type - we need to know whether it is extended */
+ /* stop reading when input blank (defaults) and all is full */
+ is_extd = 0;
+ if (fno == 0) { /* empty line */
+ if (orig && is_extended(orig->p.sys_type))
+ is_extd = 1;
+ ff = first_free(pno, is_extd, ep, format, 0, z);
+ ml = max_length(pno, is_extd, ep, format, ff, z);
+ if (ml == 0 && is_extd == 0) {
+ is_extd = 1;
+ ff = first_free(pno, is_extd, ep, format, 0, z);
+ ml = max_length(pno, is_extd, ep, format, ff, z);
+ }
+ if (ml == 0 && pno >= 4) {
+ /* no free blocks left - don't read any further */
+ warn("No room for more\n");
+ return -1;
+ }
+ }
+ if (fno < 3 || !*(fields[2]))
+ ul = orig ? orig->p.sys_type :
+ (is_extd || (pno > 3 && pct == 1 && show_extended))
+ ? EXTENDED_PARTITION : LINUX_NATIVE;
+ else if(!strcmp(fields[2], "L"))
+ ul = LINUX_NATIVE;
+ else if(!strcmp(fields[2], "S"))
+ ul = LINUX_SWAP;
+ else if(!strcmp(fields[2], "E"))
+ ul = EXTENDED_PARTITION;
+ else if(!strcmp(fields[2], "X"))
+ ul = LINUX_EXTENDED;
+ else if (get_ul(fields[2], &ul, LINUX_NATIVE, 16))
+ return 0;
+ if (ul > 255) {
+ warn("Illegal type\n");
+ return 0;
+ }
+ p.p.sys_type = ul;
+ is_extd = is_extended(ul);
+
+ /* find start */
+ ff = first_free(pno, is_extd, ep, format, 0, z);
+ ff1 = ff * unitsize(format);
+ def = orig ? orig->start : (pno > 4 && pct > 1) ? 0 : ff1;
+ if (fno < 1 || !*(fields[0]))
+ p.start = def;
+ else {
+ if (get_ul(fields[0], &ul, def / unitsize(0), 0))
+ return 0;
+ p.start = ul * unitsize(0);
+ p.start -= (p.start % unitsize(format));
+ }
+
+ /* find length */
+ ml = max_length(pno, is_extd, ep, format, p.start / unitsize(format), z);
+ ml1 = ml * unitsize(format);
+ def = orig ? orig->size : (pno > 4 && pct > 1) ? 0 : ml1;
+ if (fno < 2 || !*(fields[1]))
+ p.size = def;
+ else {
+ if (get_ul(fields[1], &ul, def / unitsize(0), 0))
+ return 0;
+ p.size = ul * unitsize(0) + unitsize(format) - 1;
+ p.size -= (p.size % unitsize(format));
+ }
+ if (p.size > ml1) {
+ warn("Warning: exceeds max allowable size (%lu)\n", ml1 / unitsize(0));
+ if (!force)
+ return 0;
+ }
+ if (p.size == 0 && pno >= 4 && (fno < 2 || !*(fields[1]))) {
+ warn("Warning: empty partition\n");
+ if (!force)
+ return 0;
+ }
+ p.p.nr_sects = p.size;
+
+ if (p.size == 0 && !orig) {
+ if(fno < 1 || !*(fields[0]))
+ p.start = 0;
+ if(fno < 3 || !*(fields[2]))
+ p.p.sys_type = EMPTY_PARTITION;
+ }
+
+ if (p.start < ff1 && p.size > 0) {
+ warn("Warning: bad partition start (earliest %lu)\n",
+ (ff1 + unitsize(0) - 1) / unitsize(0));
+ if (!force)
+ return 0;
+ }
+
+ if (fno < 4 || !*(fields[3]))
+ ul = (orig ? orig->p.bootable : 0);
+ else if (!strcmp(fields[3], "-"))
+ ul = 0;
+ else if (!strcmp(fields[3], "*") || !strcmp(fields[3], "+"))
+ ul = 0x80;
+ else {
+ warn("unrecognized bootable flag - choose - or *\n");
+ return 0;
+ }
+ p.p.bootable = ul;
+
+ if (ep && ep->p.sys_type == EMPTY_PARTITION) {
+ if(!build_surrounding_extended(&p, ep, z))
+ return 0;
+ } else
+ if(!compute_start_sect(&p, ep))
+ return 0;
+
+ { longchs aa = chs_to_longchs(p.p.begin_chs), bb;
+
+ if (fno < 5) {
+ bb = aa;
+ } else if (fno < 7) {
+ warn("partial c,h,s specification?\n");
+ return 0;
+ } else if(get_ul(fields[4], &bb.c, aa.c, 0) ||
+ get_ul(fields[5], &bb.h, aa.h, 0) ||
+ get_ul(fields[6], &bb.s, aa.s, 0))
+ return 0;
+ p.p.begin_chs = longchs_to_chs(bb);
+ }
+ { longchs aa = chs_to_longchs(p.p.end_chs), bb;
+
+ if (fno < 8) {
+ bb = aa;
+ } else if (fno < 10) {
+ warn("partial c,h,s specification?\n");
+ return 0;
+ } else if(get_ul(fields[7], &bb.c, aa.c, 0) ||
+ get_ul(fields[8], &bb.h, aa.h, 0) ||
+ get_ul(fields[9], &bb.s, aa.s, 0))
+ return 0;
+ p.p.end_chs = longchs_to_chs(bb);
+ }
+
+ if (pno > 3 && p.size && show_extended && p.p.sys_type != EMPTY_PARTITION
+ && (is_extended(p.p.sys_type) != (pct == 1))) {
+ warn("Extended partition not where expected\n");
+ if (!force)
+ return 0;
+ }
+
+ z->partitions[pno] = p;
+ if (pno >= z->partno)
+ z->partno += 4; /* reqd for out_partition() */
+
+ if (interactive)
+ out_partition(dev, 0, &(z->partitions[pno]), z);
+
+ return 1;
+}
+
+/* ep either points to the extended partition to contain this one,
+ or to the empty partition that may become extended or is 0 */
+int
+read_partition(char *dev, int interactive, int pno, struct part_desc *ep,
+ struct disk_desc *z) {
+ struct part_desc *p = &(z->partitions[pno]);
+ int i;
+
+ if (one_only) {
+ *p = oldp.partitions[pno];
+ if (one_only_pno != pno)
+ goto ret;
+ } else if (!show_extended && pno > 4 && pno%4)
+ goto ret;
+
+ while (!(i = read_line(pno, ep, dev, interactive, z)))
+ if (!interactive)
+ fatal("bad input\n");
+ if (i < 0) {
+ p->ep = ep;
+ return 0;
+ }
+
+ ret:
+ p->ep = ep;
+ if (pno >= z->partno)
+ z->partno += 4;
+ return 1;
+}
+
+void
+read_partition_chain(char *dev, int interactive, struct part_desc *ep,
+ struct disk_desc *z) {
+ int i, base;
+
+ eob = 0;
+ while (1) {
+ base = z->partno;
+ if (base+4 > SIZE(z->partitions)) {
+ printf("too many partitions\n");
+ break;
+ }
+ for (i=0; i<4; i++)
+ if (!read_partition(dev, interactive, base+i, ep, z))
+ return;
+ for (i=0; i<4; i++) {
+ ep = &(z->partitions[base+i]);
+ if (is_extended(ep->p.sys_type) && ep->size)
+ break;
+ }
+ if (i == 4) {
+ /* nothing found - maybe an empty partition is going
+ to be extended */
+ if (one_only || show_extended)
+ break;
+ ep = &(z->partitions[base+1]);
+ if (ep->size || ep->p.sys_type != EMPTY_PARTITION)
+ break;
+ }
+ }
+}
+
+void
+read_input(char *dev, int interactive, struct disk_desc *z) {
+ int i;
+ struct part_desc *partitions = &(z->partitions[0]), *ep;
+
+ for (i=0; i < SIZE(z->partitions); i++)
+ partitions[i] = zero_part_desc;
+ z->partno = 0;
+
+ if (interactive)
+ warn("
+Input in the following format; absent fields get a default value.
+<start> <size> <type [E,S,L,X,hex]> <bootable [-,*]> <c,h,s> <c,h,s>
+Usually you only need to specify <start> and <size> (and perhaps <type>).
+");
+ eof = 0;
+
+ for (i=0; i<4; i++)
+ read_partition(dev, interactive, i, 0, z);
+ for (i=0; i<4; i++) {
+ ep = partitions+i;
+ if (is_extended(ep->p.sys_type) && ep->size)
+ read_partition_chain(dev, interactive, ep, z);
+ }
+ add_sector_and_offset(z);
+}
+
+/*
+ * G. The command line
+ */
+
+static void version(void) {
+ printf(PROGNAME " version " VERSION " (aeb@cwi.nl, " DATE ")\n");
+}
+
+static void
+usage(void) {
+ version();
+ printf("Usage:
+ " PROGNAME " [options] device ...
+device: something like /dev/hda or /dev/sda
+useful options:
+ -s [or --show-size]: list size of a partition
+ -c [or --id]: print or change partition Id
+ -l [or --list]: list partitions of each device
+ -d [or --dump]: idem, but in a format suitable for later input
+ -i [or --increment]: number cylinders etc. from 1 instead of from 0
+ -uS, -uB, -uC, -uM: accept/report in units of sectors/blocks/cylinders/MB
+ -T [or --list-types]:list the known partition types
+ -D [or --DOS]: for DOS-compatibility: waste a little space
+ -R [or --re-read]: make kernel reread partition table
+ -N# : change only the partition with number #
+ -n : do not actually write to disk
+ -O file : save the sectors that will be overwritten to file
+ -I file : restore these sectors again
+ -v [or --version]: print version
+ -? [or --help]: print this message
+dangerous options:
+ -g [or --show-geometry]: print the kernel's idea of the geometry
+ -x [or --show-extended]: also list extended partitions on output
+ or expect descriptors for them on input
+ -L [or --Linux]: do not complain about things irrelevant for Linux
+ -q [or --quiet]: suppress warning messages
+ You can override the detected geometry using:
+ -C# [or --cylinders #]:set the number of cylinders to use
+ -H# [or --heads #]: set the number of heads to use
+ -S# [or --sectors #]: set the number of sectors to use
+ You can disable all consistency checking with:
+ -f [or --force]: do what I say, even if it is stupid
+");
+ exit(1);
+}
+
+static void
+activate_usage(char *progn) {
+ printf("Usage:
+ %s device list active partitions on device
+ %s device n1 n2 ... activate partitions n1 ..., inactivate the rest
+ %s device activate partition n, inactivate the other ones
+", progn, progn, PROGNAME " -An");
+ exit(1);
+}
+
+static void
+unhide_usage(char *progn) {
+ exit(1);
+}
+
+static char short_opts[] = "cdfgilnqsu:vx?1A::C:DH:I:LN:O:RS:TU::V";
+
+#define PRINT_ID 0400
+#define CHANGE_ID 01000
+
+static const struct option long_opts[] = {
+ { "change-id", no_argument, NULL, 'c' + CHANGE_ID },
+ { "print-id", no_argument, NULL, 'c' + PRINT_ID },
+ { "id", no_argument, NULL, 'c' },
+ { "dump", no_argument, NULL, 'd' },
+ { "force", no_argument, NULL, 'f' },
+ { "show-geometry", no_argument, NULL, 'g' },
+ { "increment", no_argument, NULL, 'i' },
+ { "list", no_argument, NULL, 'l' },
+ { "quiet", no_argument, NULL, 'q' },
+ { "show-size", no_argument, NULL, 's' },
+ { "unit", required_argument, NULL, 'u' },
+ { "version", no_argument, NULL, 'v' },
+ { "show-extended", no_argument, NULL, 'x' },
+ { "help", no_argument, NULL, '?' },
+ { "one-only", no_argument, NULL, '1' },
+ { "cylinders", required_argument, NULL, 'C' },
+ { "heads", required_argument, NULL, 'H' },
+ { "sectors", required_argument, NULL, 'S' },
+ { "activate", optional_argument, NULL, 'A' },
+ { "DOS", no_argument, NULL, 'D' },
+ { "Linux", no_argument, NULL, 'L' },
+ { "re-read", no_argument, NULL, 'R' },
+ { "list-types", no_argument, NULL, 'T' },
+ { "unhide", optional_argument, NULL, 'U' },
+ { "no-reread", no_argument, NULL, 160 },
+ { "IBM", no_argument, NULL, 161 },
+ { "leave-last", no_argument, NULL, 161 },
+/* undocumented flags - not all completely implemented */
+ { "in-order", no_argument, NULL, 128 },
+ { "not-in-order", no_argument, NULL, 129 },
+ { "inside-outer", no_argument, NULL, 130 },
+ { "not-inside-outer", no_argument, NULL, 131 },
+ { "nested", no_argument, NULL, 132 },
+ { "chained", no_argument, NULL, 133 },
+ { "onesector", no_argument, NULL, 134 },
+ { NULL, 0, NULL, 0 }
+};
+
+/* default devices to list */
+static struct devd {
+ char *pref, *letters;
+} defdevs[] = {
+ { "hd", "abcdefgh" },
+ { "sd", "abcde" },
+ { "xd", "ab" },
+ { "ed", "abcd" }
+};
+
+int
+is_ide_cdrom(char *device) {
+ /* No device was given explicitly, and we are trying some
+ likely things. But opening /dev/hdc may produce errors like
+ "hdc: tray open or drive not ready"
+ if it happens to be a CD-ROM drive. So try to be careful.
+ This only works since 2.1.73. */
+
+ FILE *procf;
+ char buf[100];
+ struct stat statbuf;
+
+ sprintf(buf, "/proc/ide/%s/media", device+5);
+ procf = fopen(buf, "r");
+ if (procf != NULL && fgets(buf, sizeof(buf), procf))
+ return !strncmp(buf, "cdrom", 5);
+
+ /* Now when this proc file does not exist, skip the
+ device when it is read-only. */
+ if (stat(device, &statbuf) == 0)
+ return (statbuf.st_mode & 0222) == 0;
+
+ return 0;
+}
+
+void do_list(char *dev, int silent);
+void do_size(char *dev, int silent);
+void do_geom(char *dev, int silent);
+void do_fdisk(char *dev);
+void do_reread(char *dev);
+void do_change_id(char *dev, char *part, char *id);
+void do_unhide(char **av, int ac, char *arg);
+void do_activate(char **av, int ac, char *arg);
+
+int total_size;
+
+int
+main(int argc, char **argv) {
+ char *progn;
+ int c;
+ char *dev;
+ int opt_size = 0;
+ int opt_out_geom = 0;
+ int opt_reread = 0;
+ int activate = 0;
+ int do_id = 0;
+ int unhide = 0;
+ int fdisk = 0;
+ char *activatearg = 0;
+ char *unhidearg = 0;
+
+ if (argc < 1)
+ fatal("no command?\n");
+ if ((progn = rindex(argv[0], '/')) == NULL)
+ progn = argv[0];
+ else
+ progn++;
+ if (!strcmp(progn, "activate"))
+ activate = 1; /* equivalent to `sfdisk -A' */
+#if 0 /* not important enough to deserve a name */
+ else if (!strcmp(progn, "unhide"))
+ unhide = 1; /* equivalent to `sfdisk -U' */
+#endif
+ else
+ fdisk = 1;
+
+ while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL)) != -1) {
+ switch (c) {
+ case 'f':
+ force = 1; break; /* does not imply quiet */
+ case 'g':
+ opt_out_geom = 1; break;
+ case 'i':
+ increment = 1; break;
+ case 'c':
+ case 'c' + PRINT_ID:
+ case 'c' + CHANGE_ID:
+ do_id = c; break;
+ case 'd':
+ dump = 1; /* fall through */
+ case 'l':
+ opt_list = 1; break;
+ case 'n':
+ no_write = 1; break;
+ case 'q':
+ quiet = 1; break;
+ case 's':
+ opt_size = 1; break;
+ case 'u':
+ set_format(*optarg); break;
+ case 'v':
+ version();
+ exit(0);
+ case 'x':
+ show_extended = 1; break;
+ case 'A':
+ activatearg = optarg;
+ activate = 1; break;
+ case 'C':
+ specified_cylinders = atoi(optarg); break;
+ case 'D':
+ DOS = 1; break;
+ case 'H':
+ specified_heads = atoi(optarg); break;
+ case 'L':
+ Linux = 1; break;
+ case 'N':
+ one_only = atoi(optarg); break;
+ case 'I':
+ restore_sector_file = optarg; break;
+ case 'O':
+ save_sector_file = optarg; break;
+ case 'R':
+ opt_reread = 1; break;
+ case 'S':
+ specified_sectors = atoi(optarg); break;
+ case 'T':
+ list_types();
+ exit(0);
+ case 'U':
+ unhidearg = optarg;
+ unhide = 1; break;
+ case 'V':
+ verify = 1; break;
+ case '?':
+ default:
+ usage(); break;
+
+ /* undocumented flags */
+ case 128:
+ partitions_in_order = 1; break;
+ case 129:
+ partitions_in_order = 0; break;
+ case 130:
+ all_logicals_inside_outermost_extended = 1; break;
+ case 131:
+ all_logicals_inside_outermost_extended = 0; break;
+ case 132:
+ boxes = NESTED; break;
+ case 133:
+ boxes = CHAINED; break;
+ case 134:
+ boxes = ONESECTOR; break;
+
+ /* more flags */
+ case 160:
+ no_reread = 1; break;
+ case 161:
+ leave_last = 1; break;
+ }
+ }
+
+ if (optind == argc && (opt_list || opt_out_geom || opt_size || verify)) {
+ struct devd *dp;
+ char *lp;
+ char device[10];
+
+ total_size = 0;
+
+ for(dp = defdevs; dp-defdevs < SIZE(defdevs); dp++) {
+ lp = dp->letters;
+ while(*lp) {
+ sprintf(device, "/dev/%s%c", dp->pref, *lp++);
+ if (!strcmp(dp->pref, "hd") && is_ide_cdrom(device))
+ continue;
+ if (opt_out_geom)
+ do_geom(device, 1);
+ if (opt_size)
+ do_size(device, 1);
+ if (opt_list || verify)
+ do_list(device, 1);
+ }
+ }
+
+ if (opt_size)
+ printf("total: %d blocks\n", total_size);
+
+ exit(exit_status);
+ }
+
+ if (optind == argc) {
+ if (activate)
+ activate_usage(fdisk ? "sfdisk -A" : progn);
+ else if (unhide)
+ unhide_usage(fdisk ? "sfdisk -U" : progn);
+ else
+ usage();
+ }
+
+ if (opt_list || opt_out_geom || opt_size || verify) {
+ while (optind < argc) {
+ if (opt_out_geom)
+ do_geom(argv[optind], 0);
+ if (opt_size)
+ do_size(argv[optind], 0);
+ if (opt_list || verify)
+ do_list(argv[optind], 0);
+ optind++;
+ }
+ exit(exit_status);
+ }
+
+ if (activate) {
+ do_activate(argv+optind, argc-optind, activatearg);
+ exit(exit_status);
+ }
+ if (unhide) {
+ do_unhide(argv+optind, argc-optind, unhidearg);
+ exit(exit_status);
+ }
+ if (do_id) {
+ if ((do_id & PRINT_ID) != 0 && optind != argc-2)
+ fatal("usage: sfdisk --print-id device partition-number\n");
+ else if ((do_id & CHANGE_ID) != 0 && optind != argc-3)
+ fatal("usage: sfdisk --change-id device partition-number Id\n");
+ else if (optind != argc-3 && optind != argc-2)
+ fatal("usage: sfdisk --id device partition-number [Id]\n");
+ do_change_id(argv[optind], argv[optind+1],
+ (optind == argc-2) ? 0 : argv[optind+2]);
+ exit(exit_status);
+ }
+
+ if (optind != argc-1)
+ fatal("can specify only one device (except with -l or -s)\n");
+ dev = argv[optind];
+
+ if (opt_reread)
+ do_reread(dev);
+ else if (restore_sector_file)
+ restore_sectors(dev);
+ else
+ do_fdisk(dev);
+
+ return 0;
+}
+
+/*
+ * H. Listing the current situation
+ */
+
+int
+my_open (char *dev, int rw, int silent) {
+ int fd, mode;
+
+ mode = (rw ? O_RDWR : O_RDONLY);
+ fd = open(dev, mode);
+ if (fd < 0 && !silent) {
+ perror(dev);
+ fatal("cannot open %s %s\n", dev, rw ? "read-write" : "for reading");
+ }
+ return fd;
+}
+
+void
+do_list (char *dev, int silent) {
+ int fd;
+ struct disk_desc *z;
+
+ fd = my_open(dev, 0, silent);
+ if (fd < 0)
+ return;
+
+ z = &oldp;
+
+ free_sectors();
+ get_cylindersize(dev, fd, dump ? 1 : opt_list ? 0 : 1);
+ get_partitions(dev, fd, z);
+
+ if (opt_list)
+ out_partitions(dev, z);
+
+ if (verify) {
+ if (partitions_ok(z))
+ warn("%s: OK\n", dev);
+ else
+ exit_status = 1;
+ }
+}
+
+void
+do_geom (char *dev, int silent) {
+ int fd;
+ struct hd_geometry g;
+
+ fd = my_open(dev, 0, silent);
+ if (fd < 0)
+ return;
+
+ /* get_cylindersize(dev, fd, silent); */
+ if (!ioctl(fd, HDIO_GETGEO, &g))
+ printf("%s: %d cylinders, %d heads, %d sectors/track\n",
+ dev, g.cylinders, g.heads, g.sectors);
+ else
+ printf("%s: unknown geometry\n", dev);
+}
+
+/* for compatibility with earlier fdisk: provide option -s */
+void
+do_size (char *dev, int silent) {
+ int fd, size;
+
+ fd = my_open(dev, 0, silent);
+ if (fd < 0)
+ return;
+
+ if(ioctl(fd, BLKGETSIZE, &size)) {
+ if(!silent) {
+ perror(dev);
+ fatal("BLKGETSIZE ioctl failed for %s\n", dev);
+ }
+ return;
+ }
+
+ size /= 2; /* convert sectors to blocks */
+
+ /* a CDROM drive without mounted CD yields MAXINT */
+ if (silent && size == ((1<<30)-1))
+ return;
+
+ if (silent)
+ printf("%s: %9d\n", dev, size);
+ else
+ printf("%d\n", size);
+
+ total_size += size;
+}
+
+/*
+ * Activate: usually one wants to have a single primary partition
+ * to be active. OS/2 fdisk makes non-bootable logical partitions
+ * active - I don't know what that means to OS/2 Boot Manager.
+ *
+ * Call: activate /dev/hda 2 5 7 make these partitions active
+ * and the remaining ones inactive
+ * Or: sfdisk -A /dev/hda 2 5 7
+ *
+ * If only a single partition must be active, one may also use the form
+ * sfdisk -A2 /dev/hda
+ *
+ * With "activate /dev/hda" or "sfdisk -A /dev/hda" the active partitions
+ * are listed but not changed. To get zero active partitions, use
+ * "activate /dev/hda none" or "sfdisk -A /dev/hda none".
+ * Use something like `echo ",,,*" | sfdisk -N2 /dev/hda' to only make
+ * /dev/hda2 active, without changing other partitions.
+ *
+ * A warning will be given if after the change not precisely one primary
+ * partition is active.
+ *
+ * The present syntax was chosen to be (somewhat) compatible with the
+ * activate from the LILO package.
+ */
+void
+set_active (struct disk_desc *z, char *pnam) {
+ int pno;
+
+ pno = asc_to_index(pnam, z);
+ z->partitions[pno].p.bootable = 0x80;
+}
+
+void
+do_activate (char **av, int ac, char *arg) {
+ char *dev = av[0];
+ int fd;
+ int rw, i, pno, lpno;
+ struct disk_desc *z;
+
+ z = &oldp;
+
+ rw = (!no_write && (arg || ac > 1));
+ fd = my_open(dev, rw, 0);
+
+ free_sectors();
+ get_cylindersize(dev, fd, 1);
+ get_partitions(dev, fd, z);
+
+ if (!arg && ac == 1) {
+ /* list active partitions */
+ for (pno=0; pno < z->partno; pno++) {
+ if (z->partitions[pno].p.bootable) {
+ lpno = index_to_linux(pno, z);
+ if (pno == linux_to_index(lpno, z))
+ printf("%s%d\n", dev, lpno);
+ else
+ printf("%s#%d\n", dev, pno);
+ if (z->partitions[pno].p.bootable != 0x80)
+ warn("bad active byte: 0x%x instead of 0x80\n",
+ z->partitions[pno].p.bootable);
+ }
+ }
+ } else {
+ /* clear `active byte' everywhere */
+ for (pno=0; pno < z->partno; pno++)
+ z->partitions[pno].p.bootable = 0;
+
+ /* then set where desired */
+ if (ac == 1)
+ set_active(z, arg);
+ else for(i=1; i<ac; i++)
+ set_active(z, av[i]);
+
+ /* then write to disk */
+ if(write_partitions(dev, fd, z))
+ warn("Done\n\n");
+ else
+ exit_status = 1;
+ }
+ i = 0;
+ for (pno=0; pno < z->partno && pno < 4; pno++)
+ if (z->partitions[pno].p.bootable)
+ i++;
+ if (i != 1)
+ warn("You have %d active primary partitions. This does not matter for LILO,\n"
+ "but the DOS MBR will only boot a disk with 1 active partition.\n", i);
+}
+
+void
+set_unhidden (struct disk_desc *z, char *pnam) {
+ int pno;
+ unsigned char id;
+
+ pno = asc_to_index(pnam, z);
+ id = z->partitions[pno].p.sys_type;
+ if (id == 0x11 || id == 0x14 || id == 0x16 || id == 0x17)
+ id -= 0x10;
+ else
+ fatal("partition %s has id %x and is not hidden\n", pnam, id);
+ z->partitions[pno].p.sys_type = id;
+}
+
+/*
+ * maybe remove and make part of --change-id
+ */
+void
+do_unhide (char **av, int ac, char *arg) {
+ char *dev = av[0];
+ int fd, rw, i;
+ struct disk_desc *z;
+
+ z = &oldp;
+
+ rw = !no_write;
+ fd = my_open(dev, rw, 0);
+
+ free_sectors();
+ get_cylindersize(dev, fd, 1);
+ get_partitions(dev, fd, z);
+
+ /* unhide where desired */
+ if (ac == 1)
+ set_unhidden(z, arg);
+ else for(i=1; i<ac; i++)
+ set_unhidden(z, av[i]);
+
+ /* then write to disk */
+ if(write_partitions(dev, fd, z))
+ warn("Done\n\n");
+ else
+ exit_status = 1;
+}
+
+void do_change_id(char *dev, char *pnam, char *id) {
+ int fd, rw, pno;
+ struct disk_desc *z;
+ unsigned long i;
+
+ z = &oldp;
+
+ rw = !no_write;
+ fd = my_open(dev, rw, 0);
+
+ free_sectors();
+ get_cylindersize(dev, fd, 1);
+ get_partitions(dev, fd, z);
+
+ pno = asc_to_index(pnam, z);
+ if (id == 0) {
+ printf("%x\n", z->partitions[pno].p.sys_type);
+ return;
+ }
+ i = strtoul(id, NULL, 16);
+ if (i > 255)
+ fatal("Bad Id %x\n", i);
+ z->partitions[pno].p.sys_type = i;
+
+ if(write_partitions(dev, fd, z))
+ warn("Done\n\n");
+ else
+ exit_status = 1;
+}
+
+void
+do_reread(char *dev) {
+ int fd;
+
+ fd = my_open(dev, 0, 0);
+ if(reread_ioctl(fd))
+ printf("This disk is currently in use.\n");
+}
+
+/*
+ * I. Writing the new situation
+ */
+
+void
+do_fdisk(char *dev){
+ int fd;
+ int c, answer;
+ struct stat statbuf;
+ int interactive = isatty(0);
+ struct disk_desc *z;
+
+ if (stat(dev, &statbuf) < 0) {
+ perror(dev);
+ fatal("Fatal error: cannot find %s\n", dev);
+ }
+ if (!S_ISBLK(statbuf.st_mode)) {
+ warn("Warning: %s is not a block device\n", dev);
+ }
+ fd = my_open(dev, !no_write, 0);
+
+ if(!no_write && !no_reread) {
+ warn("Checking that no-one is using this disk right now ...\n");
+ if(reread_ioctl(fd)) {
+ printf("
+This disk is currently in use - repartitioning is probably a bad idea.
+Umount all file systems, and swapoff all swap partitions on this disk.
+Use the --no-reread flag to suppress this check.\n");
+ if (!force) {
+ printf("Use the --force flag to overrule all checks.\n");
+ exit(1);
+ }
+ } else
+ warn("OK");
+ }
+
+ z = &oldp;
+
+ free_sectors();
+ get_cylindersize(dev, fd, 0);
+ get_partitions(dev, fd, z);
+
+ printf("Old situation:\n");
+ out_partitions(dev, z);
+
+ if (one_only && (one_only_pno = linux_to_index(one_only, z)) < 0)
+ fatal("Partition %d does not exist, cannot change it\n", one_only);
+
+ z = &newp;
+
+ while(1) {
+
+ read_input(dev, interactive, z);
+
+ printf("New situation:\n");
+ out_partitions(dev, z);
+
+ if (!partitions_ok(z) && !force) {
+ if(!interactive)
+ fatal("I don't like these partitions - nothing changed.\n"
+ "(If you really want this, use the --force option.)\n");
+ else
+ printf("I don't like this - probably you should answer No\n");
+ }
+ ask:
+ if (interactive) {
+ if (no_write)
+ printf("Are you satisfied with this? [ynq] ");
+ else
+ printf("Do you want to write this to disk? [ynq] ");
+ answer = c = getchar();
+ while (c != '\n' && c != EOF)
+ c = getchar();
+ if (c == EOF)
+ printf("\nsfdisk: premature end of input\n");
+ if (c == EOF || answer == 'q' || answer == 'Q') {
+ fatal("Quitting - nothing changed\n");
+ } else if (answer == 'n' || answer == 'N') {
+ continue;
+ } else if (answer == 'y' || answer == 'Y') {
+ break;
+ } else {
+ printf("Please answer one of y,n,q\n");
+ goto ask;
+ }
+ } else
+ break;
+ }
+
+ if(write_partitions(dev, fd, z))
+ printf("Successfully wrote the new partition table\n\n");
+ else
+ exit_status = 1;
+
+ reread_disk_partition(dev, fd);
+
+ warn("If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)\n"
+ "to zero the first 512 bytes: dd if=/dev/zero of=/dev/foo7 bs=512 count=1\n"
+ "(See fdisk(8).)\n");
+
+ sync(); /* superstition */
+ sleep(3);
+ exit(exit_status);
+}
diff --git a/fdisk/sfdisk.examples b/fdisk/sfdisk.examples
new file mode 100644
index 000000000..13e671d48
--- /dev/null
+++ b/fdisk/sfdisk.examples
@@ -0,0 +1,264 @@
+Examples of the use of sfdisk 3.0 (to partition a disk)
+Input lines have fields <start>,<size>,<type>... - see sfdisk.8.
+Usually no <start> is given, and input lines start with a comma.
+
+Before doing anything with a disk, make sure it is not in use;
+unmount all its file systems, and say swapoff to its swap partitions.
+(The final BLKRRPART ioctl will fail if anything else still uses
+the disk, and you will have to reboot. It is easier to first make
+sure that nothing uses the disk, e.g., by testing:
+ % umount /dev/sdb1
+ % sfdisk -R /dev/sdb
+ BLKRRPART: Device or resource busy
+ * Device busy for revalidation (usage=2)
+ % swapoff /dev/sdb3
+ % sfdisk -R /dev/sdb
+ * sdb: sdb1 < sdb5 sdb6 > sdb3
+ %
+Note that the starred messages are kernel messages, that may be
+logged somewhere, or written to some other console.
+In sfdisk 3.01 sfdisk automatically does this check, unless told not to.)
+
+1. One big partition:
+ sfdisk /dev/hda << EOF
+ ;
+ EOF
+
+(If there was garbage on the disk before, you may get error messages
+like: `ERROR: sector 0 does not have an msdos signature'
+and `/dev/hda: unrecognized partition'. This does not matter
+if you write an entirely fresh partition table anyway.)
+
+The output will be:
+-----------------------------------------------------------------------
+Old situation:
+...
+New situation:
+Units = cylinders of 208896 bytes, blocks of 1024 bytes, counting from 0
+
+ Device Boot Start End #cyls #blocks Id System
+/dev/hda1 0+ 1023 1024- 208895+ 83 Linux native
+Successfully wrote the new partition table
+ hda: hda1
+-----------------------------------------------------------------------
+Writing and rereading the partition table takes a few seconds -
+don't be alarmed if nothing happens for six seconds or so.
+
+
+2. Three primary partitions: two of size 50MB and the rest:
+ sfdisk /dev/hda -uM << EOF
+ ,50
+ ,50
+ ;
+ EOF
+-----------------------------------------------------------------------
+New situation:
+Units = megabytes of 1048576 bytes, blocks of 1024 bytes, counting from 0
+
+ Device Boot Start End MB #blocks Id System
+/dev/hda1 0+ 50- 51- 51203+ 83 Linux native
+/dev/hda2 50+ 100- 51- 51204 83 Linux native
+/dev/hda3 100+ 203 104- 106488 83 Linux native
+Successfully wrote the new partition table
+ hda: hda1 hda2 hda3
+-----------------------------------------------------------------------
+/dev/hda1 is one block (in fact only half a block) shorter than
+/dev/hda2 because its start had to be shifted away from zero in
+order to leave room for the Master Boot Record (MBR).
+
+
+3. A 1MB OS2 Boot Manager partition, a 50MB DOS partition,
+ and three extended partitions (DOS D:, Linux swap, Linux):
+ sfdisk /dev/hda -uM << EOF
+ ,1,a
+ ,50,6
+ ,,E
+ ;
+ ,20,4
+ ,16,S
+ ;
+ EOF
+-----------------------------------------------------------------------
+ Device Boot Start End MB #blocks Id System
+/dev/hda1 0+ 1- 2- 1223+ a OS/2 Boot Manager
+/dev/hda2 1+ 51- 51- 51204 6 DOS 16-bit FAT >=32M
+/dev/hda3 51+ 203 153- 156468 5 Extended
+/dev/hda4 0 - 0 0 0 Empty
+/dev/hda5 51+ 71- 21- 20603+ 4 DOS 16-bit FAT <32M
+/dev/hda6 71+ 87- 17- 16523+ 82 Linux swap
+/dev/hda7 87+ 203 117- 119339+ 83 Linux native
+Successfully wrote the new partition table
+ hda: hda1 hda2 hda3 < hda5 hda6 hda7 >
+-----------------------------------------------------------------------
+All these rounded numbers look better in cylinder units:
+ % sfdisk -l /dev/hda
+-----------------------------------------------------------------------
+ Device Boot Start End #cyls #blocks Id System
+/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager
+/dev/hda2 6 256 251 51204 6 DOS 16-bit FAT >=32M
+/dev/hda3 257 1023 767 156468 5 Extended
+/dev/hda4 0 - 0 0 0 Empty
+/dev/hda5 257+ 357 101- 20603+ 4 DOS 16-bit FAT <32M
+/dev/hda6 358+ 438 81- 16523+ 82 Linux swap
+/dev/hda7 439+ 1023 585- 119339+ 83 Linux native
+-----------------------------------------------------------------------
+But still - why does /dev/hda5 not start on a cylinder boundary?
+Because it is contained in an extended partition that does.
+Of the chain of extended partitions, usually only the first is
+shown. (The others have no name under Linux anyway.) But
+these additional extended partitions can be made visible:
+ % sfdisk -l -x /dev/hda
+-----------------------------------------------------------------------
+ Device Boot Start End #cyls #blocks Id System
+/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager
+/dev/hda2 6 256 251 51204 6 DOS 16-bit FAT >=32M
+/dev/hda3 257 1023 767 156468 5 Extended
+/dev/hda4 0 - 0 0 0 Empty
+
+/dev/hda5 257+ 357 101- 20603+ 4 DOS 16-bit FAT <32M
+ - 358 1023 666 135864 5 Extended
+ - 257 256 0 0 0 Empty
+ - 257 256 0 0 0 Empty
+
+/dev/hda6 358+ 438 81- 16523+ 82 Linux swap
+ - 439 1023 585 119340 5 Extended
+ - 358 357 0 0 0 Empty
+ - 358 357 0 0 0 Empty
+
+/dev/hda7 439+ 1023 585- 119339+ 83 Linux native
+ - 439 438 0 0 0 Empty
+ - 439 438 0 0 0 Empty
+ - 439 438 0 0 0 Empty
+-----------------------------------------------------------------------
+
+Why the empty 4th input line? The description of the extended partitions
+starts after that of the four primary partitions.
+You force an empty partition with a ",0" input line, but here all
+space was divided already, so the fourth partition became empty
+automatically.
+
+How did I know about 4,6,a,E,S? Well, E,S,L stand for Extended,
+Swap and Linux. The other values are hexadecimal and come from
+the table:
+ % sfdisk -T
+ Id Name
+
+ 0 Empty
+ 1 DOS 12-bit FAT
+ 2 XENIX root
+ 3 XENIX usr
+ 4 DOS 16-bit FAT <32M
+ 5 Extended
+ 6 DOS 16-bit FAT >=32M
+ 7 OS/2 HPFS or QNX or Advanced UNIX
+ 8 AIX data
+ 9 AIX boot or Coherent
+ a OS/2 Boot Manager
+ ...
+
+
+4. Preserving the sectors changed by sfdisk.
+ % sfdisk -O save-hdd-partition-sectors /dev/hda
+ ...
+ will write the sectors overwritten by sfdisk to file.
+ If you notice that you trashed some partition, you may
+ be able to restore things by
+ % sfdisk -I save-hdd-partition-sectors /dev/hda
+ %
+
+5. Preserving some old partitions.
+ % sfdisk -N2 /dev/hda
+ ...
+ will only change the partition /dev/hda2, and leave the rest
+ unchanged. The most obvious application is to change an Id:
+ % sfdisk -N7 /dev/hda
+ ,,63
+ %
+-----------------------------------------------------------------------
+Old situation:
+
+ Device Boot Start End #cyls #blocks Id System
+/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager
+...
+/dev/hda6 358+ 438 81- 16523+ 82 Linux swap
+/dev/hda7 439+ 1023 585- 119339+ 83 Linux native
+
+New situation:
+
+ Device Boot Start End #cyls #blocks Id System
+/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager
+...
+/dev/hda6 358+ 438 81- 16523+ 82 Linux swap
+/dev/hda7 439+ 1023 585- 119339+ 63 GNU HURD
+-----------------------------------------------------------------------
+ Note that changing a logical partition into an empty partition
+ will decrease the number of all subsequent logical partitions.
+
+6. Deleting a partition.
+At first I thought of having an option -X# for deleting partitions,
+but there are several ways in which a partition can be deleted, and
+it is probably better to handle this just as a general change.
+ % sfdisk -d /dev/hda > ohda
+will write the current tables on the file `ohda'.
+-----------------------------------------------------------------------
+% cat ohda
+# partition table of /dev/hda
+unit: sectors
+
+/dev/hda1 : start= 1, size= 40799, Id= 5
+/dev/hda2 : start= 40800, size= 40800, Id=83
+/dev/hda3 : start= 81600, size= 336192, Id=83
+/dev/hda4 : start= 0, size= 0, Id= 0
+/dev/hda5 : start= 2, size= 40798, Id=83
+-----------------------------------------------------------------------
+In order to delete the partition on /dev/hda3, edit this file
+and feed the result to sfdisk again.
+-----------------------------------------------------------------------
+% emacs ohda
+% cat ohda
+# partition table of /dev/hda
+unit: sectors
+
+/dev/hda1 : start= 1, size= 40799, Id= 5
+/dev/hda2 : start= 40800, size= 40800, Id=83
+/dev/hda3 : start= 0, size= 0, Id= 0
+/dev/hda4 : start= 0, size= 0, Id= 0
+/dev/hda5 : start= 2, size= 40798, Id=83
+% sfdisk /dev/hda < ohda
+Old situation:
+Units = cylinders of 208896 bytes, blocks of 1024 bytes, counting from 0
+
+ Device Boot Start End #cyls #blocks Id System
+/dev/hda1 0+ 99 100- 20399+ 5 Extended
+/dev/hda2 100 199 100 20400 83 Linux native
+/dev/hda3 200 1023 824 168096 83 Linux native
+/dev/hda4 0 - 0 0 0 Empty
+/dev/hda5 0+ 99 100- 20399 83 Linux native
+New situation:
+Units = sectors of 512 bytes, counting from 0
+
+ Device Boot Start End #sectors Id System
+/dev/hda1 1 40799 40799 5 Extended
+/dev/hda2 40800 81599 40800 83 Linux native
+/dev/hda3 0 - 0 0 Empty
+/dev/hda4 0 - 0 0 Empty
+/dev/hda5 2 40799 40798 83 Linux native
+Successfully wrote the new partition table
+% sfdisk -l -V /dev/hda
+
+Disk /dev/hda: 12 heads, 34 sectors, 1024 cylinders
+Units = cylinders of 208896 bytes, blocks of 1024 bytes, counting from 0
+
+ Device Boot Start End #cyls #blocks Id System
+/dev/hda1 0+ 99 100- 20399+ 5 Extended
+/dev/hda2 100 199 100 20400 83 Linux native
+/dev/hda3 0 - 0 0 0 Empty
+/dev/hda4 0 - 0 0 0 Empty
+/dev/hda5 0+ 99 100- 20399 83 Linux native
+/dev/hda: OK
+-----------------------------------------------------------------------
+This is a good way of making changes: dump the current status
+to file, edit the file, and feed it to sfdisk.
+Preserving the file on some other disk could be useful:
+if ever the MBR gets thrashed it can be used to restore
+the old situation.