summaryrefslogtreecommitdiff
path: root/i/pc104/initrd/conf/busybox/util-linux
diff options
context:
space:
mode:
Diffstat (limited to 'i/pc104/initrd/conf/busybox/util-linux')
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/Config.in509
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/Kbuild32
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/dmesg.c54
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/fbset.c408
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/fdformat.c144
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/fdisk.c3018
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/fdisk_aix.c73
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/fdisk_osf.c1063
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/fdisk_sgi.c891
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/fdisk_sun.c730
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/freeramdisk.c35
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/fsck_minix.c1390
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/getopt.c366
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/hexdump.c102
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/hwclock.c222
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/ipcrm.c218
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/ipcs.c631
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/losetup.c65
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/mdev.c270
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/minix.h76
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/mkfs_minix.c718
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/mkswap.c48
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/more.c173
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/mount.c1742
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/pivot_root.c27
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/rdate.c71
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/readprofile.c237
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/setarch.c53
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/swaponoff.c77
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/switch_root.c123
-rw-r--r--i/pc104/initrd/conf/busybox/util-linux/umount.c152
31 files changed, 13718 insertions, 0 deletions
diff --git a/i/pc104/initrd/conf/busybox/util-linux/Config.in b/i/pc104/initrd/conf/busybox/util-linux/Config.in
new file mode 100644
index 0000000..2184df1
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/Config.in
@@ -0,0 +1,509 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Linux System Utilities"
+
+config DMESG
+ bool "dmesg"
+ default n
+ help
+ dmesg is used to examine or control the kernel ring buffer. When the
+ Linux kernel prints messages to the system log, they are stored in
+ the kernel ring buffer. You can use dmesg to print the kernel's ring
+ buffer, clear the kernel ring buffer, change the size of the kernel
+ ring buffer, and change the priority level at which kernel messages
+ are also logged to the system console. Enable this option if you
+ wish to enable the 'dmesg' utility.
+
+config FEATURE_DMESG_PRETTY
+ bool "pretty dmesg output"
+ default y
+ depends on DMESG
+ help
+ If you wish to scrub the syslog level from the output, say 'Y' here.
+ The syslog level is a string prefixed to every line with the form "<#>".
+
+ With this option you will see:
+ # dmesg
+ Linux version 2.6.17.4 .....
+ BIOS-provided physical RAM map:
+ BIOS-e820: 0000000000000000 - 000000000009f000 (usable)
+
+ Without this option you will see:
+ # dmesg
+ <5>Linux version 2.6.17.4 .....
+ <6>BIOS-provided physical RAM map:
+ <6> BIOS-e820: 0000000000000000 - 000000000009f000 (usable)
+
+config FBSET
+ bool "fbset"
+ default n
+ help
+ fbset is used to show or change the settings of a Linux frame buffer
+ device. The frame buffer device provides a simple and unique
+ interface to access a graphics display. Enable this option
+ if you wish to enable the 'fbset' utility.
+
+config FEATURE_FBSET_FANCY
+ bool "Turn on extra fbset options"
+ default n
+ depends on FBSET
+ help
+ This option enables extended fbset options, allowing one to set the
+ framebuffer size, color depth, etc. interface to access a graphics
+ display. Enable this option if you wish to enable extended fbset
+ options.
+
+config FEATURE_FBSET_READMODE
+ bool "Turn on fbset readmode support"
+ default n
+ depends on FBSET
+ help
+ This option allows fbset to read the video mode database stored by
+ default as /etc/fb.modes, which can be used to set frame buffer
+ device to pre-defined video modes.
+
+config FDFLUSH
+ bool "fdflush"
+ default n
+ help
+ fdflush is only needed when changing media on slightly-broken
+ removable media drives. It is used to make Linux believe that a
+ hardware disk-change switch has been actuated, which causes Linux to
+ forget anything it has cached from the previous media. If you have
+ such a slightly-broken drive, you will need to run fdflush every time
+ you change a disk. Most people have working hardware and can safely
+ leave this disabled.
+
+config FDFORMAT
+ bool "fdformat"
+ default n
+ help
+ fdformat is used to low-level format a floppy disk.
+
+config FDISK
+ bool "fdisk"
+ default n
+ help
+ The fdisk utility is used to divide hard disks into one or more
+ logical disks, which are generally called partitions. This utility
+ can be used to list and edit the set of partitions or BSD style
+ 'disk slices' that are defined on a hard drive.
+
+config FDISK_SUPPORT_LARGE_DISKS
+ bool "support over 4GB disks"
+ default y
+ depends on FDISK
+ help
+ Enable this option to support large disks > 4GB.
+
+config FEATURE_FDISK_WRITABLE
+ bool "Write support"
+ default y
+ depends on FDISK
+ help
+ Enabling this option allows you to create or change a partition table
+ and write those changes out to disk. If you leave this option
+ disabled, you will only be able to view the partition table.
+
+config FEATURE_AIX_LABEL
+ bool "Support AIX disklabels"
+ default n
+ depends on FDISK && FEATURE_FDISK_WRITABLE
+ help
+ Enabling this option allows you to create or change AIX disklabels.
+ Most people can safely leave this option disabled.
+
+config FEATURE_SGI_LABEL
+ bool "Support SGI disklabels"
+ default n
+ depends on FDISK && FEATURE_FDISK_WRITABLE
+ help
+ Enabling this option allows you to create or change SGI disklabels.
+ Most people can safely leave this option disabled.
+
+config FEATURE_SUN_LABEL
+ bool "Support SUN disklabels"
+ default n
+ depends on FDISK && FEATURE_FDISK_WRITABLE
+ help
+ Enabling this option allows you to create or change SUN disklabels.
+ Most people can safely leave this option disabled.
+
+config FEATURE_OSF_LABEL
+ bool "Support BSD disklabels"
+ default n
+ depends on FDISK && FEATURE_FDISK_WRITABLE
+ help
+ Enabling this option allows you to create or change BSD disklabels
+ and define and edit BSD disk slices.
+
+config FEATURE_FDISK_ADVANCED
+ bool "Support expert mode"
+ default n
+ depends on FDISK && FEATURE_FDISK_WRITABLE
+ help
+ Enabling this option allows you to do terribly unsafe things like
+ define arbitrary drive geometry, move the beginning of data in a
+ partition, and similarly evil things. Unless you have a very good
+ reason you would be wise to leave this disabled.
+
+config FREERAMDISK
+ bool "freeramdisk"
+ default n
+ help
+ Linux allows you to create ramdisks. This utility allows you to
+ delete them and completely free all memory that was used for the
+ ramdisk. For example, if you boot Linux into a ramdisk and later
+ pivot_root, you may want to free the memory that is allocated to the
+ ramdisk. If you have no use for freeing memory from a ramdisk, leave
+ this disabled.
+
+config FSCK_MINIX
+ bool "fsck_minix"
+ default n
+ help
+ The minix filesystem is a nice, small, compact, read-write filesystem
+ with little overhead. It is not a journaling filesystem however and
+ can experience corruption if it is not properly unmounted or if the
+ power goes off in the middle of a write. This utility allows you to
+ check for and attempt to repair any corruption that occurs to a minix
+ filesystem.
+
+config MKFS_MINIX
+ bool "mkfs_minix"
+ default n
+ help
+ The minix filesystem is a nice, small, compact, read-write filesystem
+ with little overhead. If you wish to be able to create minix filesystems
+ this utility will do the job for you.
+
+comment "Minix filesystem support"
+ depends on FSCK_MINIX || MKFS_MINIX
+
+config FEATURE_MINIX2
+ bool "Support Minix fs v2 (fsck_minix/mkfs_minix)"
+ default y
+ depends on FSCK_MINIX || MKFS_MINIX
+ help
+ If you wish to be able to create version 2 minix filesystems, enable this.
+ If you enabled 'mkfs_minix' then you almost certainly want to be using the
+ version 2 filesystem support.
+
+config GETOPT
+ bool "getopt"
+ default n
+ help
+ The getopt utility is used to break up (parse) options in command
+ lines to make it easy to write complex shell scripts that also check
+ for legal (and illegal) options. If you want to write horribly
+ complex shell scripts, or use some horribly complex shell script
+ written by others, this utility may be for you. Most people will
+ wisely leave this disabled.
+
+config HEXDUMP
+ bool "hexdump"
+ default n
+ help
+ The hexdump utility is used to display binary data in a readable
+ way that is comparable to the output from most hex editors.
+
+config HWCLOCK
+ bool "hwclock"
+ default n
+ help
+ The hwclock utility is used to read and set the hardware clock
+ on a system. This is primarily used to set the current time on
+ shutdown in the hardware clock, so the hardware will keep the
+ correct time when Linux is _not_ running.
+
+config FEATURE_HWCLOCK_LONG_OPTIONS
+ bool "Support long options (--hctosys,...)"
+ default n
+ depends on HWCLOCK && GETOPT_LONG
+ help
+ By default, the hwclock utility only uses short options. If you
+ are overly fond of its long options, such as --hctosys, --utc, etc)
+ then enable this option.
+
+config FEATURE_HWCLOCK_ADJTIME_FHS
+ bool "Use FHS /var/lib/hwclock/adjtime"
+ default y
+ depends on HWCLOCK
+ help
+ Starting with FHS 2.3, the adjtime state file is supposed to exist
+ at /var/lib/hwclock/adjtime instead of /etc/adjtime. If you wish
+ to use the FHS behavior, answer Y here, otherwise answer N for the
+ classic /etc/adjtime path.
+
+ http://www.pathname.com/fhs/pub/fhs-2.3.html#VARLIBHWCLOCKSTATEDIRECTORYFORHWCLO
+
+config IPCRM
+ bool "ipcrm"
+ default n
+ select FEATURE_SUID
+ help
+ The ipcrm utility allows the removal of System V interprocess
+ communication (IPC) objects and the associated data structures
+ from the system.
+
+config IPCS
+ bool "ipcs"
+ default n
+ select FEATURE_SUID
+ help
+ The ipcs utility is used to provide information on the currently
+ allocated System V interprocess (IPC) objects in the system.
+
+config LOSETUP
+ bool "losetup"
+ default n
+ help
+ losetup is used to associate or detach a loop device with a regular
+ file or block device, and to query the status of a loop device. This
+ version does not currently support enabling data encryption.
+
+config MDEV
+ bool "mdev"
+ default n
+ help
+ mdev is a mini-udev implementation for dynamically creating device
+ nodes in the /dev directory.
+
+ For more information, please see docs/mdev.txt
+
+config FEATURE_MDEV_CONF
+ bool "Support /etc/mdev.conf"
+ default n
+ depends on MDEV
+ help
+ Add support for the mdev config file to control ownership and
+ permissions of the device nodes.
+
+ For more information, please see docs/mdev.txt
+
+config FEATURE_MDEV_EXEC
+ bool "Support command execution at device addition/removal"
+ default n
+ depends on FEATURE_MDEV_CONF
+ help
+ This adds support for an optional field to /etc/mdev.conf for
+ executing commands when devices are created/removed.
+
+ For more information, please see docs/mdev.txt
+
+config MKSWAP
+ bool "mkswap"
+ default n
+ help
+ The mkswap utility is used to configure a file or disk partition as
+ Linux swap space. This allows Linux to use the entire file or
+ partition as if it were additional RAM, which can greatly increase
+ the capability of low-memory machines. This additional memory is
+ much slower than real RAM, but can be very helpful at preventing your
+ applications being killed by the Linux out of memory (OOM) killer.
+ Once you have created swap space using 'mkswap' you need to enable
+ the swap space using the 'swapon' utility.
+
+config FEATURE_MKSWAP_V0
+ bool "version 0 support"
+ default n
+ depends on MKSWAP
+# depends on MKSWAP && DEPRECATED
+ help
+ Enable support for the old v0 style.
+ If your kernel is older than 2.1.117, then v0 support is the
+ only option.
+
+config MORE
+ bool "more"
+ default n
+ help
+ more is a simple utility which allows you to read text one screen
+ sized page at a time. If you want to read text that is larger than
+ the screen, and you are using anything faster than a 300 baud modem,
+ you will probably find this utility very helpful. If you don't have
+ any need to reading text files, you can leave this disabled.
+
+config FEATURE_USE_TERMIOS
+ bool "Use termios to manipulate the screen"
+ default y
+ depends on MORE
+ help
+ This option allows utilities such as 'more' and 'top' to determine
+ the size of the screen. If you leave this disabled, your utilities
+ that display things on the screen will be especially primitive and
+ will be unable to determine the current screen size, and will be
+ unable to move the cursor.
+
+config MOUNT
+ bool "mount"
+ default n
+ help
+ All files and filesystems in Unix are arranged into one big directory
+ tree. The 'mount' utility is used to graft a filesystem onto a
+ particular part of the tree. A filesystem can either live on a block
+ device, or it can be accessible over the network, as is the case with
+ NFS filesystems. Most people using BusyBox will also want to enable
+ the 'mount' utility.
+
+config FEATURE_MOUNT_NFS
+ bool "Support mounting NFS file systems"
+ default n
+ depends on MOUNT && FEATURE_HAVE_RPC
+ select FEATURE_SYSLOG
+ help
+ Enable mounting of NFS file systems.
+
+config FEATURE_MOUNT_CIFS
+ bool "Support mounting CIFS/SMB file systems"
+ default n
+ depends on MOUNT
+ help
+ Enable support for samba mounts.
+
+config FEATURE_MOUNT_FLAGS
+ depends on MOUNT
+ bool "Support lots of -o flags in mount"
+ default y
+ help
+ Without this, mount only supports ro/rw/remount. With this, it
+ supports nosuid, suid, dev, nodev, exec, noexec, sync, async, atime,
+ noatime, diratime, nodiratime, loud, bind, move, shared, slave,
+ private, unbindable, rshared, rslave, rprivate, and runbindable.
+
+config FEATURE_MOUNT_FSTAB
+ depends on MOUNT
+ bool "Support /etc/fstab and -a"
+ default y
+ help
+ Support mount all and looking for files in /etc/fstab.
+
+config PIVOT_ROOT
+ bool "pivot_root"
+ default n
+ help
+ The pivot_root utility swaps the mount points for the root filesystem
+ with some other mounted filesystem. This allows you to do all sorts
+ of wild and crazy things with your Linux system and is far more
+ powerful than 'chroot'.
+
+ Note: This is for initrd in linux 2.4. Under initramfs (introduced
+ in linux 2.6) use switch_root instead.
+
+config RDATE
+ bool "rdate"
+ default n
+ help
+ The rdate utility allows you to synchronize the date and time of your
+ system clock with the date and time of a remote networked system using
+ the RFC868 protocol, which is built into the inetd daemon on most
+ systems.
+
+config READPROFILE
+ bool "readprofile"
+ default n
+ help
+ This allows you to parse /proc/profile for basic profiling.
+
+config SETARCH
+ bool "setarch"
+ default n
+ help
+ The linux32 utility is used to create a 32bit environment for the
+ specified program (usually a shell). It only makes sense to have
+ this util on a system that supports both 64bit and 32bit userland
+ (like amd64/x86, ppc64/ppc, sparc64/sparc, etc...).
+
+config SWAPONOFF
+ bool "swaponoff"
+ default n
+ help
+ This option enables both the 'swapon' and the 'swapoff' utilities.
+ Once you have created some swap space using 'mkswap', you also need
+ to enable your swap space with the 'swapon' utility. The 'swapoff'
+ utility is used, typically at system shutdown, to disable any swap
+ space. If you are not using any swap space, you can leave this
+ option disabled.
+
+config SWITCH_ROOT
+ bool "switch_root"
+ default n
+ help
+ The switch_root utility is used from initramfs to select a new
+ root device. Under initramfs, you have to use this instead of
+ pivot_root. (Stop reading here if you don't care why.)
+
+ Booting with initramfs extracts a gzipped cpio archive into rootfs
+ (which is a variant of ramfs/tmpfs). Because rootfs can't be moved
+ or unmounted*, pivot_root will not work from initramfs. Instead,
+ switch_root deletes everything out of rootfs (including itself),
+ does a mount --move that overmounts rootfs with the new root, and
+ then execs the specified init program.
+
+ * Because the Linux kernel uses rootfs internally as the starting
+ and ending point for searching through the kernel's doubly linked
+ list of active mount points. That's why.
+
+config UMOUNT
+ bool "umount"
+ default n
+ help
+ When you want to remove a mounted filesystem from its current mount point,
+ for example when you are shutting down the system, the 'umount' utility is
+ the tool to use. If you enabled the 'mount' utility, you almost certainly
+ also want to enable 'umount'.
+
+config FEATURE_UMOUNT_ALL
+ bool "umount -a option"
+ default n
+ depends on UMOUNT
+ help
+ Support -a option to unmount all currently mounted filesystems.
+
+comment "Common options for mount/umount"
+ depends on MOUNT || UMOUNT
+
+config FEATURE_MOUNT_LOOP
+ bool "Support loopback mounts"
+ default n
+ depends on MOUNT || UMOUNT
+ help
+ Enabling this feature allows automatic mounting of files (containing
+ filesystem images) via the linux kernel's loopback devices. The mount
+ command will detect you are trying to mount a file instead of a block
+ device, and transparently associate the file with a loopback device.
+ The umount command will also free that loopback device.
+
+ You can still use the 'losetup' utility (to manually associate files
+ with loop devices) if you need to do something advanced, such as
+ specify an offset or cryptographic options to the loopback device.
+ (If you don't want umount to free the loop device, use "umount -D".)
+
+config FEATURE_MTAB_SUPPORT
+ bool "Support for the old /etc/mtab file"
+ default n
+ depends on MOUNT || UMOUNT
+ help
+ Historically, Unix systems kept track of the currently mounted
+ partitions in the file "/etc/mtab". These days, the kernel exports
+ the list of currently mounted partitions in "/proc/mounts", rendering
+ the old mtab file obsolete. (In modern systems, /etc/mtab should be
+ a symlink to /proc/mounts.)
+
+ The only reason to have mount maintain an /etc/mtab file itself is if
+ your stripped-down embedded system does not have a /proc directory.
+ If you must use this, keep in mind it's inherently brittle (for
+ example a mount under chroot won't update it), can't handle modern
+ features like separate per-process filesystem namespaces, requires
+ that your /etc directory be writeable, tends to get easily confused
+ by --bind or --move mounts, won't update if you rename a directory
+ that contains a mount point, and so on. (In brief: avoid.)
+
+ About the only reason to use this is if you've removed /proc from
+ your kernel.
+
+endmenu
+
diff --git a/i/pc104/initrd/conf/busybox/util-linux/Kbuild b/i/pc104/initrd/conf/busybox/util-linux/Kbuild
new file mode 100644
index 0000000..cc1d0e0
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/Kbuild
@@ -0,0 +1,32 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+lib-y:=
+lib-$(CONFIG_DMESG) +=dmesg.o
+lib-$(CONFIG_FBSET) +=fbset.o
+lib-$(CONFIG_FDFLUSH) +=freeramdisk.o
+lib-$(CONFIG_FDFORMAT) +=fdformat.o
+lib-$(CONFIG_FDISK) +=fdisk.o
+lib-$(CONFIG_FREERAMDISK) +=freeramdisk.o
+lib-$(CONFIG_FSCK_MINIX) +=fsck_minix.o
+lib-$(CONFIG_GETOPT) +=getopt.o
+lib-$(CONFIG_HEXDUMP) +=hexdump.o
+lib-$(CONFIG_HWCLOCK) +=hwclock.o
+lib-$(CONFIG_IPCRM) +=ipcrm.o
+lib-$(CONFIG_IPCS) +=ipcs.o
+lib-$(CONFIG_LOSETUP) +=losetup.o
+lib-$(CONFIG_MDEV) +=mdev.o
+lib-$(CONFIG_MKFS_MINIX) +=mkfs_minix.o
+lib-$(CONFIG_MKSWAP) +=mkswap.o
+lib-$(CONFIG_MORE) +=more.o
+lib-$(CONFIG_MOUNT) +=mount.o
+lib-$(CONFIG_PIVOT_ROOT) +=pivot_root.o
+lib-$(CONFIG_RDATE) +=rdate.o
+lib-$(CONFIG_READPROFILE) +=readprofile.o
+lib-$(CONFIG_SETARCH) +=setarch.o
+lib-$(CONFIG_SWAPONOFF) +=swaponoff.o
+lib-$(CONFIG_SWITCH_ROOT) +=switch_root.o
+lib-$(CONFIG_UMOUNT) +=umount.o
diff --git a/i/pc104/initrd/conf/busybox/util-linux/dmesg.c b/i/pc104/initrd/conf/busybox/util-linux/dmesg.c
new file mode 100644
index 0000000..0bbc306
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/dmesg.c
@@ -0,0 +1,54 @@
+/* vi: set sw=4 ts=4: */
+/*
+ *
+ * dmesg - display/control kernel ring buffer.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ * Copyright 2006 Bernhard Fischer <rep.nop@aon.at>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include "busybox.h"
+#include <unistd.h>
+#include <sys/klog.h>
+
+int dmesg_main(int argc, char *argv[]);
+int dmesg_main(int argc, char *argv[])
+{
+ char *size, *level;
+ int flags = getopt32(argc, argv, "cs:n:", &size, &level);
+
+ if (flags & 4) {
+ if (klogctl(8, NULL, xatoul_range(level, 0, 10)))
+ bb_perror_msg_and_die("klogctl");
+ } else {
+ int len;
+ char *buf;
+
+ len = (flags & 2) ? xatoul_range(size, 2, INT_MAX) : 16384;
+ buf = xmalloc(len);
+ if (0 > (len = klogctl(3 + (flags & 1), buf, len)))
+ bb_perror_msg_and_die("klogctl");
+
+ // Skip <#> at the start of lines, and make sure we end with a newline.
+
+ if (ENABLE_FEATURE_DMESG_PRETTY) {
+ int last = '\n';
+ int in;
+
+ for (in = 0; in<len;) {
+ if (last == '\n' && buf[in] == '<') in += 3;
+ else putchar(last = buf[in++]);
+ }
+ if (last != '\n') putchar('\n');
+ } else {
+ write(1,buf,len);
+ if (len && buf[len-1]!='\n') putchar('\n');
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP) free(buf);
+ }
+
+ return 0;
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/fbset.c b/i/pc104/initrd/conf/busybox/util-linux/fbset.c
new file mode 100644
index 0000000..bd584e4
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/fbset.c
@@ -0,0 +1,408 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini fbset implementation for busybox
+ *
+ * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * This is a from-scratch implementation of fbset; but the de facto fbset
+ * implementation was a good reference. fbset (original) is released under
+ * the GPL, and is (c) 1995-1999 by:
+ * Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ */
+
+#include "busybox.h"
+
+#define DEFAULTFBDEV FB_0
+#define DEFAULTFBMODE "/etc/fb.modes"
+
+enum {
+ OPT_CHANGE = (1 << 0),
+ OPT_INFO = (1 << 1),
+ OPT_READMODE = (1 << 2),
+ OPT_ALL = (1 << 9),
+
+ CMD_FB = 1,
+ CMD_DB = 2,
+ CMD_GEOMETRY = 3,
+ CMD_TIMING = 4,
+ CMD_ACCEL = 5,
+ CMD_HSYNC = 6,
+ CMD_VSYNC = 7,
+ CMD_LACED = 8,
+ CMD_DOUBLE = 9,
+/* CMD_XCOMPAT = 10, */
+ CMD_ALL = 11,
+ CMD_INFO = 12,
+ CMD_CHANGE = 13,
+
+#ifdef CONFIG_FEATURE_FBSET_FANCY
+ CMD_XRES = 100,
+ CMD_YRES = 101,
+ CMD_VXRES = 102,
+ CMD_VYRES = 103,
+ CMD_DEPTH = 104,
+ CMD_MATCH = 105,
+ CMD_PIXCLOCK = 106,
+ CMD_LEFT = 107,
+ CMD_RIGHT = 108,
+ CMD_UPPER = 109,
+ CMD_LOWER = 110,
+ CMD_HSLEN = 111,
+ CMD_VSLEN = 112,
+ CMD_CSYNC = 113,
+ CMD_GSYNC = 114,
+ CMD_EXTSYNC = 115,
+ CMD_BCAST = 116,
+ CMD_RGBA = 117,
+ CMD_STEP = 118,
+ CMD_MOVE = 119,
+#endif
+};
+
+static unsigned g_options;
+
+/* Stuff stolen from the kernel's fb.h */
+#define FB_ACTIVATE_ALL 64
+enum {
+ FBIOGET_VSCREENINFO = 0x4600,
+ FBIOPUT_VSCREENINFO = 0x4601
+};
+struct fb_bitfield {
+ uint32_t offset; /* beginning of bitfield */
+ uint32_t length; /* length of bitfield */
+ uint32_t msb_right; /* !=0: Most significant bit is right */
+};
+struct fb_var_screeninfo {
+ uint32_t xres; /* visible resolution */
+ uint32_t yres;
+ uint32_t xres_virtual; /* virtual resolution */
+ uint32_t yres_virtual;
+ uint32_t xoffset; /* offset from virtual to visible */
+ uint32_t yoffset; /* resolution */
+
+ uint32_t bits_per_pixel;
+ uint32_t grayscale; /* !=0 Graylevels instead of colors */
+
+ struct fb_bitfield red; /* bitfield in fb mem if true color, */
+ struct fb_bitfield green; /* else only length is significant */
+ struct fb_bitfield blue;
+ struct fb_bitfield transp; /* transparency */
+
+ uint32_t nonstd; /* !=0 Non standard pixel format */
+
+ uint32_t activate; /* see FB_ACTIVATE_x */
+
+ uint32_t height; /* height of picture in mm */
+ uint32_t width; /* width of picture in mm */
+
+ uint32_t accel_flags; /* acceleration flags (hints) */
+
+ /* Timing: All values in pixclocks, except pixclock (of course) */
+ uint32_t pixclock; /* pixel clock in ps (pico seconds) */
+ uint32_t left_margin; /* time from sync to picture */
+ uint32_t right_margin; /* time from picture to sync */
+ uint32_t upper_margin; /* time from sync to picture */
+ uint32_t lower_margin;
+ uint32_t hsync_len; /* length of horizontal sync */
+ uint32_t vsync_len; /* length of vertical sync */
+ uint32_t sync; /* see FB_SYNC_x */
+ uint32_t vmode; /* see FB_VMODE_x */
+ uint32_t reserved[6]; /* Reserved for future compatibility */
+};
+
+
+static const struct cmdoptions_t {
+ const char name[10];
+ const unsigned char param_count;
+ const unsigned char code;
+} g_cmdoptions[] = {
+ { "-fb", 1, CMD_FB },
+ { "-db", 1, CMD_DB },
+ { "-a", 0, CMD_ALL },
+ { "-i", 0, CMD_INFO },
+ { "-g", 5, CMD_GEOMETRY },
+ { "-t", 7, CMD_TIMING },
+ { "-accel", 1, CMD_ACCEL },
+ { "-hsync", 1, CMD_HSYNC },
+ { "-vsync", 1, CMD_VSYNC },
+ { "-laced", 1, CMD_LACED },
+ { "-double", 1, CMD_DOUBLE },
+ { "-n", 0, CMD_CHANGE },
+#ifdef CONFIG_FEATURE_FBSET_FANCY
+ { "-all", 0, CMD_ALL },
+ { "-xres", 1, CMD_XRES },
+ { "-yres", 1, CMD_YRES },
+ { "-vxres", 1, CMD_VXRES },
+ { "-vyres", 1, CMD_VYRES },
+ { "-depth", 1, CMD_DEPTH },
+ { "-match", 0, CMD_MATCH },
+ { "-geometry", 5, CMD_GEOMETRY },
+ { "-pixclock", 1, CMD_PIXCLOCK },
+ { "-left", 1, CMD_LEFT },
+ { "-right", 1, CMD_RIGHT },
+ { "-upper", 1, CMD_UPPER },
+ { "-lower", 1, CMD_LOWER },
+ { "-hslen", 1, CMD_HSLEN },
+ { "-vslen", 1, CMD_VSLEN },
+ { "-timings", 7, CMD_TIMING },
+ { "-csync", 1, CMD_CSYNC },
+ { "-gsync", 1, CMD_GSYNC },
+ { "-extsync", 1, CMD_EXTSYNC },
+ { "-bcast", 1, CMD_BCAST },
+ { "-rgba", 1, CMD_RGBA },
+ { "-step", 1, CMD_STEP },
+ { "-move", 1, CMD_MOVE },
+#endif
+ { "", 0, 0 }
+};
+
+#ifdef CONFIG_FEATURE_FBSET_READMODE
+/* taken from linux/fb.h */
+enum {
+ FB_VMODE_INTERLACED = 1, /* interlaced */
+ FB_VMODE_DOUBLE = 2, /* double scan */
+ FB_SYNC_HOR_HIGH_ACT = 1, /* horizontal sync high active */
+ FB_SYNC_VERT_HIGH_ACT = 2, /* vertical sync high active */
+ FB_SYNC_EXT = 4, /* external sync */
+ FB_SYNC_COMP_HIGH_ACT = 8 /* composite sync high active */
+};
+#endif
+
+static int readmode(struct fb_var_screeninfo *base, const char *fn,
+ const char *mode)
+{
+#ifdef CONFIG_FEATURE_FBSET_READMODE
+ FILE *f;
+ char buf[256];
+ char *p = buf;
+
+ f = xfopen(fn, "r");
+ while (!feof(f)) {
+ fgets(buf, sizeof(buf), f);
+ if (!(p = strstr(buf, "mode ")) && !(p = strstr(buf, "mode\t")))
+ continue;
+ p += 5;
+ if (!(p = strstr(buf, mode)))
+ continue;
+ p += strlen(mode);
+ if (!isspace(*p) && (*p != 0) && (*p != '"')
+ && (*p != '\r') && (*p != '\n'))
+ continue; /* almost, but not quite */
+
+ while (!feof(f)) {
+ fgets(buf, sizeof(buf), f);
+ if ((p = strstr(buf, "geometry "))) {
+ p += 9;
+ /* FIXME: catastrophic on arches with 64bit ints */
+ sscanf(p, "%d %d %d %d %d",
+ &(base->xres), &(base->yres),
+ &(base->xres_virtual), &(base->yres_virtual),
+ &(base->bits_per_pixel));
+ } else if ((p = strstr(buf, "timings "))) {
+ p += 8;
+ sscanf(p, "%d %d %d %d %d %d %d",
+ &(base->pixclock),
+ &(base->left_margin), &(base->right_margin),
+ &(base->upper_margin), &(base->lower_margin),
+ &(base->hsync_len), &(base->vsync_len));
+ } else if ((p = strstr(buf, "laced "))) {
+ //p += 6;
+ if (strstr(buf, "false")) {
+ base->vmode &= ~FB_VMODE_INTERLACED;
+ } else {
+ base->vmode |= FB_VMODE_INTERLACED;
+ }
+ } else if ((p = strstr(buf, "double "))) {
+ //p += 7;
+ if (strstr(buf, "false")) {
+ base->vmode &= ~FB_VMODE_DOUBLE;
+ } else {
+ base->vmode |= FB_VMODE_DOUBLE;
+ }
+ } else if ((p = strstr(buf, "vsync "))) {
+ //p += 6;
+ if (strstr(buf, "low")) {
+ base->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+ } else {
+ base->sync |= FB_SYNC_VERT_HIGH_ACT;
+ }
+ } else if ((p = strstr(buf, "hsync "))) {
+ //p += 6;
+ if (strstr(buf, "low")) {
+ base->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+ } else {
+ base->sync |= FB_SYNC_HOR_HIGH_ACT;
+ }
+ } else if ((p = strstr(buf, "csync "))) {
+ //p += 6;
+ if (strstr(buf, "low")) {
+ base->sync &= ~FB_SYNC_COMP_HIGH_ACT;
+ } else {
+ base->sync |= FB_SYNC_COMP_HIGH_ACT;
+ }
+ } else if ((p = strstr(buf, "extsync "))) {
+ //p += 8;
+ if (strstr(buf, "false")) {
+ base->sync &= ~FB_SYNC_EXT;
+ } else {
+ base->sync |= FB_SYNC_EXT;
+ }
+ }
+
+ if (strstr(buf, "endmode"))
+ return 1;
+ }
+ }
+#else
+ bb_error_msg("mode reading not compiled in");
+#endif
+ return 0;
+}
+
+static inline void setmode(struct fb_var_screeninfo *base,
+ struct fb_var_screeninfo *set)
+{
+ if ((int) set->xres > 0)
+ base->xres = set->xres;
+ if ((int) set->yres > 0)
+ base->yres = set->yres;
+ if ((int) set->xres_virtual > 0)
+ base->xres_virtual = set->xres_virtual;
+ if ((int) set->yres_virtual > 0)
+ base->yres_virtual = set->yres_virtual;
+ if ((int) set->bits_per_pixel > 0)
+ base->bits_per_pixel = set->bits_per_pixel;
+}
+
+static inline void showmode(struct fb_var_screeninfo *v)
+{
+ double drate = 0, hrate = 0, vrate = 0;
+
+ if (v->pixclock) {
+ drate = 1e12 / v->pixclock;
+ hrate = drate / (v->left_margin + v->xres + v->right_margin + v->hsync_len);
+ vrate = hrate / (v->upper_margin + v->yres + v->lower_margin + v->vsync_len);
+ }
+ printf("\nmode \"%ux%u-%u\"\n"
+#ifdef CONFIG_FEATURE_FBSET_FANCY
+ "\t# D: %.3f MHz, H: %.3f kHz, V: %.3f Hz\n"
+#endif
+ "\tgeometry %u %u %u %u %u\n"
+ "\ttimings %u %u %u %u %u %u %u\n"
+ "\taccel %s\n"
+ "\trgba %u/%u,%u/%u,%u/%u,%u/%u\n"
+ "endmode\n\n",
+ v->xres, v->yres, (int) (vrate + 0.5),
+#ifdef CONFIG_FEATURE_FBSET_FANCY
+ drate / 1e6, hrate / 1e3, vrate,
+#endif
+ v->xres, v->yres, v->xres_virtual, v->yres_virtual, v->bits_per_pixel,
+ v->pixclock, v->left_margin, v->right_margin, v->upper_margin, v->lower_margin,
+ v->hsync_len, v->vsync_len,
+ (v->accel_flags > 0 ? "true" : "false"),
+ v->red.length, v->red.offset, v->green.length, v->green.offset,
+ v->blue.length, v->blue.offset, v->transp.length, v->transp.offset);
+}
+
+#ifdef STANDALONE
+int main(int argc, char **argv)
+#else
+int fbset_main(int argc, char **argv);
+int fbset_main(int argc, char **argv)
+#endif
+{
+ struct fb_var_screeninfo var, varset;
+ int fh, i;
+ const char *fbdev = DEFAULTFBDEV;
+ const char *modefile = DEFAULTFBMODE;
+ char *thisarg, *mode = NULL;
+
+ memset(&varset, 0xFF, sizeof(varset));
+
+ /* parse cmd args.... why do they have to make things so difficult? */
+ argv++;
+ argc--;
+ for (; argc > 0 && (thisarg = *argv); argc--, argv++) {
+ for (i = 0; g_cmdoptions[i].name[0]; i++) {
+ if (strcmp(thisarg, g_cmdoptions[i].name))
+ continue;
+ if (argc-1 < g_cmdoptions[i].param_count)
+ bb_show_usage();
+
+ switch (g_cmdoptions[i].code) {
+ case CMD_FB:
+ fbdev = argv[1];
+ break;
+ case CMD_DB:
+ modefile = argv[1];
+ break;
+ case CMD_GEOMETRY:
+ varset.xres = xatou32(argv[1]);
+ varset.yres = xatou32(argv[2]);
+ varset.xres_virtual = xatou32(argv[3]);
+ varset.yres_virtual = xatou32(argv[4]);
+ varset.bits_per_pixel = xatou32(argv[5]);
+ break;
+ case CMD_TIMING:
+ varset.pixclock = xatou32(argv[1]);
+ varset.left_margin = xatou32(argv[2]);
+ varset.right_margin = xatou32(argv[3]);
+ varset.upper_margin = xatou32(argv[4]);
+ varset.lower_margin = xatou32(argv[5]);
+ varset.hsync_len = xatou32(argv[6]);
+ varset.vsync_len = xatou32(argv[7]);
+ break;
+ case CMD_ALL:
+ g_options |= OPT_ALL;
+ break;
+ case CMD_CHANGE:
+ g_options |= OPT_CHANGE;
+ break;
+#ifdef CONFIG_FEATURE_FBSET_FANCY
+ case CMD_XRES:
+ varset.xres = xatou32(argv[1]);
+ break;
+ case CMD_YRES:
+ varset.yres = xatou32(argv[1]);
+ break;
+ case CMD_DEPTH:
+ varset.bits_per_pixel = xatou32(argv[1]);
+ break;
+#endif
+ }
+ argc -= g_cmdoptions[i].param_count;
+ argv += g_cmdoptions[i].param_count;
+ break;
+ }
+ if (!g_cmdoptions[i].name[0]) {
+ if (argc != 1)
+ bb_show_usage();
+ mode = *argv;
+ g_options |= OPT_READMODE;
+ }
+ }
+
+ fh = xopen(fbdev, O_RDONLY);
+ if (ioctl(fh, FBIOGET_VSCREENINFO, &var))
+ bb_perror_msg_and_die("ioctl(%sT_VSCREENINFO)", "GE");
+ if (g_options & OPT_READMODE) {
+ if (!readmode(&var, modefile, mode)) {
+ bb_error_msg_and_die("unknown video mode '%s'", mode);
+ }
+ }
+
+ setmode(&var, &varset);
+ if (g_options & OPT_CHANGE) {
+ if (g_options & OPT_ALL)
+ var.activate = FB_ACTIVATE_ALL;
+ if (ioctl(fh, FBIOPUT_VSCREENINFO, &var))
+ bb_perror_msg_and_die("ioctl(%sT_VSCREENINFO)", "PU");
+ }
+ showmode(&var);
+ /* Don't close the file, as exiting will take care of that */
+ /* close(fh); */
+
+ return EXIT_SUCCESS;
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/fdformat.c b/i/pc104/initrd/conf/busybox/util-linux/fdformat.c
new file mode 100644
index 0000000..d694bd6
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/fdformat.c
@@ -0,0 +1,144 @@
+/* vi: set sw=4 ts=4: */
+/* fdformat.c - Low-level formats a floppy disk - Werner Almesberger */
+
+/* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
+ * - added Native Language Support
+ * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ * - more i18n/nls translatable strings marked
+ *
+ * 5 July 2003 -- modified for Busybox by Erik Andersen
+ */
+
+#include "busybox.h"
+
+
+/* Stuff extracted from linux/fd.h */
+struct floppy_struct {
+ unsigned int size, /* nr of sectors total */
+ sect, /* sectors per track */
+ head, /* nr of heads */
+ track, /* nr of tracks */
+ stretch; /* !=0 means double track steps */
+#define FD_STRETCH 1
+#define FD_SWAPSIDES 2
+
+ unsigned char gap, /* gap1 size */
+
+ rate, /* data rate. |= 0x40 for perpendicular */
+#define FD_2M 0x4
+#define FD_SIZECODEMASK 0x38
+#define FD_SIZECODE(floppy) (((((floppy)->rate&FD_SIZECODEMASK)>> 3)+ 2) %8)
+#define FD_SECTSIZE(floppy) ( (floppy)->rate & FD_2M ? \
+ 512 : 128 << FD_SIZECODE(floppy) )
+#define FD_PERP 0x40
+
+ spec1, /* stepping rate, head unload time */
+ fmt_gap; /* gap2 size */
+ const char * name; /* used only for predefined formats */
+};
+struct format_descr {
+ unsigned int device,head,track;
+};
+#define FDFMTBEG _IO(2,0x47)
+#define FDFMTTRK _IOW(2,0x48, struct format_descr)
+#define FDFMTEND _IO(2,0x49)
+#define FDGETPRM _IOR(2, 0x04, struct floppy_struct)
+#define FD_FILL_BYTE 0xF6 /* format fill byte. */
+
+static void xioctl(int fd, int request, void *argp, const char *string)
+{
+ if (ioctl(fd, request, argp) < 0) {
+ bb_perror_msg_and_die(string);
+ }
+}
+
+int fdformat_main(int argc,char **argv);
+int fdformat_main(int argc,char **argv)
+{
+ int fd, n, cyl, read_bytes, verify;
+ unsigned char *data;
+ struct stat st;
+ struct floppy_struct param;
+ struct format_descr descr;
+
+ if (argc < 2) {
+ bb_show_usage();
+ }
+ verify = !getopt32(argc, argv, "n");
+ argv += optind;
+
+ xstat(*argv, &st);
+ if (!S_ISBLK(st.st_mode)) {
+ bb_error_msg_and_die("%s: not a block device", *argv);
+ /* do not test major - perhaps this was an USB floppy */
+ }
+
+ /* O_RDWR for formatting and verifying */
+ fd = xopen(*argv, O_RDWR);
+
+ /* original message was: "Could not determine current format type" */
+ xioctl(fd, FDGETPRM, &param, "FDGETPRM");
+
+ printf("%s-sided, %d tracks, %d sec/track. Total capacity %d kB\n",
+ (param.head == 2) ? "Double" : "Single",
+ param.track, param.sect, param.size >> 1);
+
+ /* FORMAT */
+ printf("Formatting... ");
+ xioctl(fd, FDFMTBEG, NULL, "FDFMTBEG");
+
+ /* n == track */
+ for (n = 0; n < param.track; n++) {
+ descr.head = 0;
+ descr.track = n;
+ xioctl(fd, FDFMTTRK, &descr, "FDFMTTRK");
+ printf("%3d\b\b\b", n);
+ if (param.head == 2) {
+ descr.head = 1;
+ xioctl(fd, FDFMTTRK, &descr, "FDFMTTRK");
+ }
+ }
+
+ xioctl(fd, FDFMTEND, NULL, "FDFMTEND");
+ printf("done\n");
+
+ /* VERIFY */
+ if (verify) {
+ /* n == cyl_size */
+ n = param.sect*param.head*512;
+
+ data = xmalloc(n);
+ printf("Verifying... ");
+ for (cyl = 0; cyl < param.track; cyl++) {
+ printf("%3d\b\b\b", cyl);
+ read_bytes = safe_read(fd, data, n);
+ if (read_bytes != n) {
+ if (read_bytes < 0) {
+ bb_perror_msg(bb_msg_read_error);
+ }
+ bb_error_msg_and_die("problem reading cylinder %d, "
+ "expected %d, read %d", cyl, n, read_bytes);
+ // FIXME: maybe better seek & continue??
+ }
+ /* Check backwards so we don't need a counter */
+ while (--read_bytes >= 0) {
+ if (data[read_bytes] != FD_FILL_BYTE) {
+ printf("bad data in cyl %d\nContinuing... ",cyl);
+ }
+ }
+ }
+ /* There is no point in freeing blocks at the end of a program, because
+ all of the program's space is given back to the system when the process
+ terminates.*/
+
+ if (ENABLE_FEATURE_CLEAN_UP) free(data);
+
+ printf("done\n");
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP) close(fd);
+
+ /* Don't bother closing. Exit does
+ * that, so we can save a few bytes */
+ return EXIT_SUCCESS;
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/fdisk.c b/i/pc104/initrd/conf/busybox/util-linux/fdisk.c
new file mode 100644
index 0000000..f3c7ca4
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/fdisk.c
@@ -0,0 +1,3018 @@
+/* vi: set sw=4 ts=4: */
+/* fdisk.c -- Partition table manipulator for Linux.
+ *
+ * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
+ * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (initial bb port)
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include <assert.h> /* assert */
+#include "busybox.h"
+
+/* Looks like someone forgot to add this to config system */
+#ifndef ENABLE_FEATURE_FDISK_BLKSIZE
+# define ENABLE_FEATURE_FDISK_BLKSIZE 0
+# define USE_FEATURE_FDISK_BLKSIZE(a)
+#endif
+
+#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
+
+#define DEFAULT_SECTOR_SIZE 512
+#define MAX_SECTOR_SIZE 2048
+#define SECTOR_SIZE 512 /* still used in osf/sgi/sun 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 LINUX_LVM 0x8e
+#define LINUX_RAID 0xfd
+
+struct hd_geometry {
+ unsigned char heads;
+ unsigned char sectors;
+ unsigned short cylinders;
+ unsigned long start;
+};
+
+#define HDIO_GETGEO 0x0301 /* get device geometry */
+
+static const char msg_building_new_label[] =
+"Building a new %s. Changes will remain in memory only,\n"
+"until you decide to write them. After that the previous content\n"
+"won't be recoverable.\n\n";
+
+static const char msg_part_already_defined[] =
+"Partition %d is already defined, delete it before re-adding\n";
+
+
+static unsigned sector_size = DEFAULT_SECTOR_SIZE;
+static unsigned user_set_sector_size;
+static unsigned sector_offset = 1;
+
+#if ENABLE_FEATURE_OSF_LABEL
+static int possibly_osf_label;
+#endif
+
+static unsigned heads, sectors, cylinders;
+static void update_units(void);
+
+
+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 */
+} ATTRIBUTE_PACKED;
+
+enum failure {
+ ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
+ unable_to_write
+};
+
+enum label_type {
+ label_dos, label_sun, label_sgi, label_aix, label_osf
+};
+
+#define LABEL_IS_DOS (label_dos == current_label_type)
+
+#if ENABLE_FEATURE_SUN_LABEL
+#define LABEL_IS_SUN (label_sun == current_label_type)
+#define STATIC_SUN static
+#else
+#define LABEL_IS_SUN 0
+#define STATIC_SUN extern
+#endif
+
+#if ENABLE_FEATURE_SGI_LABEL
+#define LABEL_IS_SGI (label_sgi == current_label_type)
+#define STATIC_SGI static
+#else
+#define LABEL_IS_SGI 0
+#define STATIC_SGI extern
+#endif
+
+#if ENABLE_FEATURE_AIX_LABEL
+#define LABEL_IS_AIX (label_aix == current_label_type)
+#define STATIC_AIX static
+#else
+#define LABEL_IS_AIX 0
+#define STATIC_AIX extern
+#endif
+
+#if ENABLE_FEATURE_OSF_LABEL
+#define LABEL_IS_OSF (label_osf == current_label_type)
+#define STATIC_OSF static
+#else
+#define LABEL_IS_OSF 0
+#define STATIC_OSF extern
+#endif
+
+enum action { fdisk, require, try_only, create_empty_dos, create_empty_sun };
+
+static enum label_type current_label_type;
+
+static const char *disk_device;
+static int fd; /* the disk */
+static int partitions = 4; /* maximum partition + 1 */
+static int display_in_cyl_units = 1;
+static unsigned units_per_sector = 1;
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static void change_units(void);
+static void reread_partition_table(int leave);
+static void delete_partition(int i);
+static int get_partition(int warn, int max);
+static void list_types(const char *const *sys);
+static unsigned read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg);
+#endif
+static const char *partition_type(unsigned char type);
+static void fdisk_fatal(enum failure why) ATTRIBUTE_NORETURN;
+static void get_geometry(void);
+static int get_boot(enum action what);
+
+#define PLURAL 0
+#define SINGULAR 1
+
+static unsigned get_start_sect(const struct partition *p);
+static unsigned get_nr_sects(const struct partition *p);
+
+/*
+ * per partition table entry data
+ *
+ * The four primary partitions have the same sectorbuffer (MBRbuffer)
+ * and have NULL ext_pointer.
+ * Each logical partition table entry has two pointers, one for the
+ * partition and one link to the next one.
+ */
+struct pte {
+ struct partition *part_table; /* points into sectorbuffer */
+ struct partition *ext_pointer; /* points into sectorbuffer */
+ off_t offset; /* disk sector number */
+ char *sectorbuffer; /* disk sector contents */
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ char changed; /* boolean */
+#endif
+};
+
+/* DOS partition types */
+
+static const char *const i386_sys_types[] = {
+ "\x00" "Empty",
+ "\x01" "FAT12",
+ "\x04" "FAT16 <32M",
+ "\x05" "Extended", /* DOS 3.3+ extended partition */
+ "\x06" "FAT16", /* DOS 16-bit >=32M */
+ "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
+ "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
+ "\x0b" "Win95 FAT32",
+ "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
+ "\x0e" "Win95 FAT16 (LBA)",
+ "\x0f" "Win95 Ext'd (LBA)",
+ "\x11" "Hidden FAT12",
+ "\x12" "Compaq diagnostics",
+ "\x14" "Hidden FAT16 <32M",
+ "\x16" "Hidden FAT16",
+ "\x17" "Hidden HPFS/NTFS",
+ "\x1b" "Hidden Win95 FAT32",
+ "\x1c" "Hidden W95 FAT32 (LBA)",
+ "\x1e" "Hidden W95 FAT16 (LBA)",
+ "\x3c" "Part.Magic recovery",
+ "\x41" "PPC PReP Boot",
+ "\x42" "SFS",
+ "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
+ "\x80" "Old Minix", /* Minix 1.4a and earlier */
+ "\x81" "Minix / old Linux",/* Minix 1.4b and later */
+ "\x82" "Linux swap", /* also Solaris */
+ "\x83" "Linux",
+ "\x84" "OS/2 hidden C: drive",
+ "\x85" "Linux extended",
+ "\x86" "NTFS volume set",
+ "\x87" "NTFS volume set",
+ "\x8e" "Linux LVM",
+ "\x9f" "BSD/OS", /* BSDI */
+ "\xa0" "Thinkpad hibernation",
+ "\xa5" "FreeBSD", /* various BSD flavours */
+ "\xa6" "OpenBSD",
+ "\xa8" "Darwin UFS",
+ "\xa9" "NetBSD",
+ "\xab" "Darwin boot",
+ "\xb7" "BSDI fs",
+ "\xb8" "BSDI swap",
+ "\xbe" "Solaris boot",
+ "\xeb" "BeOS fs",
+ "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
+ "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
+ "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
+ "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
+ "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
+ autodetect using persistent
+ superblock */
+#if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
+ "\x02" "XENIX root",
+ "\x03" "XENIX usr",
+ "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
+ "\x09" "AIX bootable", /* AIX data or Coherent */
+ "\x10" "OPUS",
+ "\x18" "AST SmartSleep",
+ "\x24" "NEC DOS",
+ "\x39" "Plan 9",
+ "\x40" "Venix 80286",
+ "\x4d" "QNX4.x",
+ "\x4e" "QNX4.x 2nd part",
+ "\x4f" "QNX4.x 3rd part",
+ "\x50" "OnTrack DM",
+ "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
+ "\x52" "CP/M", /* CP/M or Microport SysV/AT */
+ "\x53" "OnTrack DM6 Aux3",
+ "\x54" "OnTrackDM6",
+ "\x55" "EZ-Drive",
+ "\x56" "Golden Bow",
+ "\x5c" "Priam Edisk",
+ "\x61" "SpeedStor",
+ "\x64" "Novell Netware 286",
+ "\x65" "Novell Netware 386",
+ "\x70" "DiskSecure Multi-Boot",
+ "\x75" "PC/IX",
+ "\x93" "Amoeba",
+ "\x94" "Amoeba BBT", /* (bad block table) */
+ "\xa7" "NeXTSTEP",
+ "\xbb" "Boot Wizard hidden",
+ "\xc1" "DRDOS/sec (FAT-12)",
+ "\xc4" "DRDOS/sec (FAT-16 < 32M)",
+ "\xc6" "DRDOS/sec (FAT-16)",
+ "\xc7" "Syrinx",
+ "\xda" "Non-FS data",
+ "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
+ Concurrent DOS or CTOS */
+ "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
+ "\xdf" "BootIt", /* BootIt EMBRM */
+ "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
+ extended partition */
+ "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
+ "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
+ partition < 1024 cyl. */
+ "\xf1" "SpeedStor",
+ "\xf4" "SpeedStor", /* SpeedStor large partition */
+ "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
+ "\xff" "BBT", /* Xenix Bad Block Table */
+#endif
+ NULL
+};
+
+
+/* Globals */
+
+struct globals {
+ char *line_ptr;
+ char line_buffer[80];
+ char partname_buffer[80];
+ jmp_buf listingbuf;
+ /* Raw disk label. For DOS-type partition tables the MBR,
+ * with descriptions of the primary partitions. */
+ char MBRbuffer[MAX_SECTOR_SIZE];
+ /* Partition tables */
+ struct pte ptes[MAXIMUM_PARTS];
+};
+/* bb_common_bufsiz1 is too small for this on 64 bit CPUs */
+#define G (*ptr_to_globals)
+
+#define line_ptr (G.line_ptr)
+#define listingbuf (G.listingbuf)
+#define line_buffer (G.line_buffer)
+#define partname_buffer (G.partname_buffer)
+#define MBRbuffer (G.MBRbuffer)
+#define ptes (G.ptes)
+
+
+/* Code */
+
+#define IS_EXTENDED(i) \
+ ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
+
+#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
+
+#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
+
+#define pt_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) \
+ do { \
+ s = sector % sectors + 1; \
+ sector /= sectors; \
+ h = sector % heads; \
+ sector /= heads; \
+ c = sector & 0xff; \
+ s |= (sector >> 2) & 0xc0; \
+ } while (0)
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+/* read line; return 0 or first printable char */
+static int
+read_line(const char *prompt)
+{
+ int sz;
+
+ sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
+ if (sz <= 0)
+ exit(0); /* Ctrl-D or Ctrl-C */
+
+ if (line_buffer[sz-1] == '\n')
+ line_buffer[--sz] = '\0';
+
+ line_ptr = line_buffer;
+ while (*line_ptr && !isgraph(*line_ptr))
+ line_ptr++;
+ return *line_ptr;
+}
+#endif
+
+/*
+ * return partition name - uses static storage
+ */
+static const char *
+partname(const char *dev, int pno, int lth)
+{
+ const char *p;
+ int w, wp;
+ int bufsiz;
+ char *bufp;
+
+ bufp = partname_buffer;
+ bufsiz = sizeof(partname_buffer);
+
+ w = strlen(dev);
+ p = "";
+
+ if (isdigit(dev[w-1]))
+ p = "p";
+
+ /* devfs kludge - note: fdisk partition names are not supposed
+ to equal kernel names, so there is no reason to do this */
+ if (strcmp(dev + w - 4, "disc") == 0) {
+ w -= 4;
+ p = "part";
+ }
+
+ wp = strlen(p);
+
+ if (lth) {
+ snprintf(bufp, bufsiz, "%*.*s%s%-2u",
+ lth-wp-2, w, dev, p, pno);
+ } else {
+ snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
+ }
+ return bufp;
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static void
+set_all_unchanged(void)
+{
+ int i;
+
+ for (i = 0; i < MAXIMUM_PARTS; i++)
+ ptes[i].changed = 0;
+}
+
+static ATTRIBUTE_ALWAYS_INLINE void
+set_changed(int i)
+{
+ ptes[i].changed = 1;
+}
+#endif /* FEATURE_FDISK_WRITABLE */
+
+static ATTRIBUTE_ALWAYS_INLINE struct partition *
+get_part_table(int i)
+{
+ return ptes[i].part_table;
+}
+
+static const char *
+str_units(int n)
+{ /* n==1: use singular */
+ if (n == 1)
+ return display_in_cyl_units ? "cylinder" : "sector";
+ return display_in_cyl_units ? "cylinders" : "sectors";
+}
+
+static int
+valid_part_table_flag(const char *mbuffer)
+{
+ return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static ATTRIBUTE_ALWAYS_INLINE void
+write_part_table_flag(char *b)
+{
+ b[510] = 0x55;
+ b[511] = 0xaa;
+}
+
+static char
+read_nonempty(const char *mesg)
+{
+ while (!read_line(mesg)) /* repeat */;
+ return *line_ptr;
+}
+
+static char
+read_maybe_empty(const char *mesg)
+{
+ if (!read_line(mesg)) {
+ line_ptr = line_buffer;
+ line_ptr[0] = '\n';
+ line_ptr[1] = '\0';
+ }
+ return line_ptr[0];
+}
+
+static int
+read_hex(const char *const *sys)
+{
+ unsigned long v;
+ while (1) {
+ read_nonempty("Hex code (type L to list codes): ");
+ if (*line_ptr == 'l' || *line_ptr == 'L') {
+ list_types(sys);
+ continue;
+ }
+ v = bb_strtoul(line_ptr, NULL, 16);
+ if (v > 0xff)
+ /* Bad input also triggers this */
+ continue;
+ return v;
+ }
+}
+#endif /* FEATURE_FDISK_WRITABLE */
+
+#include "fdisk_aix.c"
+
+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_partinfo {
+ uint32_t start_cylinder;
+ uint32_t num_sectors;
+ } partitions[8];
+ unsigned short magic; /* Magic number */
+ unsigned short csum; /* Label xor'd checksum */
+} sun_partition;
+#define sunlabel ((sun_partition *)MBRbuffer)
+STATIC_OSF void bsd_select(void);
+STATIC_OSF void xbsd_print_disklabel(int);
+#include "fdisk_osf.c"
+
+#if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
+static uint16_t
+fdisk_swap16(uint16_t x)
+{
+ return (x << 8) | (x >> 8);
+}
+
+static uint32_t
+fdisk_swap32(uint32_t x)
+{
+ return (x << 24) |
+ ((x & 0xFF00) << 8) |
+ ((x & 0xFF0000) >> 8) |
+ (x >> 24);
+}
+#endif
+
+STATIC_SGI const char *const sgi_sys_types[];
+STATIC_SGI unsigned sgi_get_num_sectors(int i);
+STATIC_SGI int sgi_get_sysid(int i);
+STATIC_SGI void sgi_delete_partition(int i);
+STATIC_SGI void sgi_change_sysid(int i, int sys);
+STATIC_SGI void sgi_list_table(int xtra);
+#if ENABLE_FEATURE_FDISK_ADVANCED
+STATIC_SGI void sgi_set_xcyl(void);
+#endif
+STATIC_SGI int verify_sgi(int verbose);
+STATIC_SGI void sgi_add_partition(int n, int sys);
+STATIC_SGI void sgi_set_swappartition(int i);
+STATIC_SGI const char *sgi_get_bootfile(void);
+STATIC_SGI void sgi_set_bootfile(const char* aFile);
+STATIC_SGI void create_sgiinfo(void);
+STATIC_SGI void sgi_write_table(void);
+STATIC_SGI void sgi_set_bootpartition(int i);
+#include "fdisk_sgi.c"
+
+STATIC_SUN const char *const sun_sys_types[];
+STATIC_SUN void sun_delete_partition(int i);
+STATIC_SUN void sun_change_sysid(int i, int sys);
+STATIC_SUN void sun_list_table(int xtra);
+STATIC_SUN void add_sun_partition(int n, int sys);
+#if ENABLE_FEATURE_FDISK_ADVANCED
+STATIC_SUN void sun_set_alt_cyl(void);
+STATIC_SUN void sun_set_ncyl(int cyl);
+STATIC_SUN void sun_set_xcyl(void);
+STATIC_SUN void sun_set_ilfact(void);
+STATIC_SUN void sun_set_rspeed(void);
+STATIC_SUN void sun_set_pcylcount(void);
+#endif
+STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
+STATIC_SUN void verify_sun(void);
+STATIC_SUN void sun_write_table(void);
+#include "fdisk_sun.c"
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+/* start_sect and nr_sects are stored little endian on all machines */
+/* moreover, they are not aligned correctly */
+static void
+store4_little_endian(unsigned char *cp, unsigned val)
+{
+ cp[0] = val;
+ cp[1] = val >> 8;
+ cp[2] = val >> 16;
+ cp[3] = val >> 24;
+}
+#endif /* FEATURE_FDISK_WRITABLE */
+
+static unsigned
+read4_little_endian(const unsigned char *cp)
+{
+ return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static void
+set_start_sect(struct partition *p, unsigned start_sect)
+{
+ store4_little_endian(p->start4, start_sect);
+}
+#endif
+
+static unsigned
+get_start_sect(const struct partition *p)
+{
+ return read4_little_endian(p->start4);
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static void
+set_nr_sects(struct partition *p, unsigned nr_sects)
+{
+ store4_little_endian(p->size4, nr_sects);
+}
+#endif
+
+static unsigned
+get_nr_sects(const struct partition *p)
+{
+ return read4_little_endian(p->size4);
+}
+
+/* normally O_RDWR, -l option gives O_RDONLY */
+static int type_open = O_RDWR;
+
+
+static int ext_index; /* the prime extended partition */
+static int listing; /* no aborts for fdisk -l */
+static int dos_compatible_flag = ~0;
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static int dos_changed;
+static int nowarn; /* no warnings for fdisk -l/-s */
+#endif
+
+
+
+static unsigned user_cylinders, user_heads, user_sectors;
+static unsigned pt_heads, pt_sectors;
+static unsigned kern_heads, kern_sectors;
+
+static off_t extended_offset; /* offset of link pointers */
+
+static unsigned long long total_number_of_sectors;
+
+
+static void fdisk_fatal(enum failure why)
+{
+ const char *message;
+
+ if (listing) {
+ close(fd);
+ longjmp(listingbuf, 1);
+ }
+
+ switch (why) {
+ case unable_to_open:
+ message = "cannot open %s";
+ break;
+ case unable_to_read:
+ message = "cannot read from %s";
+ break;
+ case unable_to_seek:
+ message = "cannot seek on %s";
+ break;
+ case unable_to_write:
+ message = "cannot write to %s";
+ break;
+ case ioctl_error:
+ message = "BLKGETSIZE ioctl failed on %s";
+ break;
+ default:
+ message = "fatal error";
+ }
+
+ bb_error_msg_and_die(message, disk_device);
+}
+
+static void
+seek_sector(off_t secno)
+{
+ off_t offset = secno * sector_size;
+ if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
+ fdisk_fatal(unable_to_seek);
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static void
+write_sector(off_t secno, char *buf)
+{
+ seek_sector(secno);
+ if (write(fd, buf, sector_size) != sector_size)
+ fdisk_fatal(unable_to_write);
+}
+#endif
+
+/* Allocate a buffer and read a partition table sector */
+static void
+read_pte(struct pte *pe, off_t offset)
+{
+ pe->offset = offset;
+ pe->sectorbuffer = xmalloc(sector_size);
+ seek_sector(offset);
+ if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
+ fdisk_fatal(unable_to_read);
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ pe->changed = 0;
+#endif
+ pe->part_table = pe->ext_pointer = NULL;
+}
+
+static unsigned
+get_partition_start(const struct pte *pe)
+{
+ return pe->offset + get_start_sect(pe->part_table);
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+/*
+ * Avoid warning about DOS partitions when no DOS partition was changed.
+ * Here a heuristic "is probably dos partition".
+ * We might also do the opposite and warn in all cases except
+ * for "is probably nondos partition".
+ */
+static int
+is_dos_partition(int t)
+{
+ return (t == 1 || t == 4 || t == 6 ||
+ t == 0x0b || t == 0x0c || t == 0x0e ||
+ t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
+ t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
+ t == 0xc1 || t == 0xc4 || t == 0xc6);
+}
+
+static void
+menu(void)
+{
+ puts("Command Action");
+ if (LABEL_IS_SUN) {
+ puts("a\ttoggle a read only flag"); /* sun */
+ puts("b\tedit bsd disklabel");
+ puts("c\ttoggle the mountable flag"); /* sun */
+ puts("d\tdelete a partition");
+ puts("l\tlist known partition types");
+ puts("n\tadd a new partition");
+ puts("o\tcreate a new empty DOS partition table");
+ puts("p\tprint the partition table");
+ puts("q\tquit without saving changes");
+ puts("s\tcreate a new empty Sun disklabel"); /* sun */
+ puts("t\tchange a partition's system id");
+ puts("u\tchange display/entry units");
+ puts("v\tverify the partition table");
+ puts("w\twrite table to disk and exit");
+#if ENABLE_FEATURE_FDISK_ADVANCED
+ puts("x\textra functionality (experts only)");
+#endif
+ } else if (LABEL_IS_SGI) {
+ puts("a\tselect bootable partition"); /* sgi flavour */
+ puts("b\tedit bootfile entry"); /* sgi */
+ puts("c\tselect sgi swap partition"); /* sgi flavour */
+ puts("d\tdelete a partition");
+ puts("l\tlist known partition types");
+ puts("n\tadd a new partition");
+ puts("o\tcreate a new empty DOS partition table");
+ puts("p\tprint the partition table");
+ puts("q\tquit without saving changes");
+ puts("s\tcreate a new empty Sun disklabel"); /* sun */
+ puts("t\tchange a partition's system id");
+ puts("u\tchange display/entry units");
+ puts("v\tverify the partition table");
+ puts("w\twrite table to disk and exit");
+ } else if (LABEL_IS_AIX) {
+ puts("o\tcreate a new empty DOS partition table");
+ puts("q\tquit without saving changes");
+ puts("s\tcreate a new empty Sun disklabel"); /* sun */
+ } else {
+ puts("a\ttoggle a bootable flag");
+ puts("b\tedit bsd disklabel");
+ puts("c\ttoggle the dos compatibility flag");
+ puts("d\tdelete a partition");
+ puts("l\tlist known partition types");
+ puts("n\tadd a new partition");
+ puts("o\tcreate a new empty DOS partition table");
+ puts("p\tprint the partition table");
+ puts("q\tquit without saving changes");
+ puts("s\tcreate a new empty Sun disklabel"); /* sun */
+ puts("t\tchange a partition's system id");
+ puts("u\tchange display/entry units");
+ puts("v\tverify the partition table");
+ puts("w\twrite table to disk and exit");
+#if ENABLE_FEATURE_FDISK_ADVANCED
+ puts("x\textra functionality (experts only)");
+#endif
+ }
+}
+#endif /* FEATURE_FDISK_WRITABLE */
+
+
+#if ENABLE_FEATURE_FDISK_ADVANCED
+static void
+xmenu(void)
+{
+ puts("Command Action");
+ if (LABEL_IS_SUN) {
+ puts("a\tchange number of alternate cylinders"); /*sun*/
+ puts("c\tchange number of cylinders");
+ puts("d\tprint the raw data in the partition table");
+ puts("e\tchange number of extra sectors per cylinder");/*sun*/
+ puts("h\tchange number of heads");
+ puts("i\tchange interleave factor"); /*sun*/
+ puts("o\tchange rotation speed (rpm)"); /*sun*/
+ puts("p\tprint the partition table");
+ puts("q\tquit without saving changes");
+ puts("r\treturn to main menu");
+ puts("s\tchange number of sectors/track");
+ puts("v\tverify the partition table");
+ puts("w\twrite table to disk and exit");
+ puts("y\tchange number of physical cylinders"); /*sun*/
+ } else if (LABEL_IS_SGI) {
+ puts("b\tmove beginning of data in a partition"); /* !sun */
+ puts("c\tchange number of cylinders");
+ puts("d\tprint the raw data in the partition table");
+ puts("e\tlist extended partitions"); /* !sun */
+ puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
+ puts("h\tchange number of heads");
+ puts("p\tprint the partition table");
+ puts("q\tquit without saving changes");
+ puts("r\treturn to main menu");
+ puts("s\tchange number of sectors/track");
+ puts("v\tverify the partition table");
+ puts("w\twrite table to disk and exit");
+ } else if (LABEL_IS_AIX) {
+ puts("b\tmove beginning of data in a partition"); /* !sun */
+ puts("c\tchange number of cylinders");
+ puts("d\tprint the raw data in the partition table");
+ puts("e\tlist extended partitions"); /* !sun */
+ puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
+ puts("h\tchange number of heads");
+ puts("p\tprint the partition table");
+ puts("q\tquit without saving changes");
+ puts("r\treturn to main menu");
+ puts("s\tchange number of sectors/track");
+ puts("v\tverify the partition table");
+ puts("w\twrite table to disk and exit");
+ } else {
+ puts("b\tmove beginning of data in a partition"); /* !sun */
+ puts("c\tchange number of cylinders");
+ puts("d\tprint the raw data in the partition table");
+ puts("e\tlist extended partitions"); /* !sun */
+ puts("f\tfix partition order"); /* !sun, !aix, !sgi */
+#if ENABLE_FEATURE_SGI_LABEL
+ puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
+#endif
+ puts("h\tchange number of heads");
+ puts("p\tprint the partition table");
+ puts("q\tquit without saving changes");
+ puts("r\treturn to main menu");
+ puts("s\tchange number of sectors/track");
+ puts("v\tverify the partition table");
+ puts("w\twrite table to disk and exit");
+ }
+}
+#endif /* ADVANCED mode */
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static const char *const *
+get_sys_types(void)
+{
+ return (
+ LABEL_IS_SUN ? sun_sys_types :
+ LABEL_IS_SGI ? sgi_sys_types :
+ i386_sys_types);
+}
+#else
+#define get_sys_types() i386_sys_types
+#endif /* FEATURE_FDISK_WRITABLE */
+
+static const char *
+partition_type(unsigned char type)
+{
+ int i;
+ const char *const *types = get_sys_types();
+
+ for (i = 0; types[i]; i++)
+ if ((unsigned char)types[i][0] == type)
+ return types[i] + 1;
+
+ return "Unknown";
+}
+
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static int
+get_sysid(int i)
+{
+ return LABEL_IS_SUN ? sunlabel->infos[i].id :
+ (LABEL_IS_SGI ? sgi_get_sysid(i) :
+ ptes[i].part_table->sys_ind);
+}
+
+static void
+list_types(const char *const *sys)
+{
+ enum { COLS = 3 };
+
+ unsigned last[COLS];
+ unsigned done, next, size;
+ int i;
+
+ for (size = 0; sys[size]; size++) /* */;
+
+ done = 0;
+ for (i = COLS-1; i >= 0; i--) {
+ done += (size + i - done) / (i + 1);
+ last[COLS-1 - i] = done;
+ }
+
+ i = done = next = 0;
+ do {
+ printf("%c%2x %-22.22s", i ? ' ' : '\n',
+ (unsigned char)sys[next][0],
+ sys[next] + 1);
+ next = last[i++] + done;
+ if (i >= COLS || next >= last[i]) {
+ i = 0;
+ next = ++done;
+ }
+ } while (done < last[0]);
+ putchar('\n');
+}
+#endif /* FEATURE_FDISK_WRITABLE */
+
+static int
+is_cleared_partition(const struct partition *p)
+{
+ return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
+ p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
+ get_start_sect(p) || get_nr_sects(p));
+}
+
+static void
+clear_partition(struct partition *p)
+{
+ if (!p)
+ return;
+ memset(p, 0, sizeof(struct partition));
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static void
+set_partition(int i, int doext, off_t start, off_t stop, int sysid)
+{
+ struct partition *p;
+ off_t offset;
+
+ if (doext) {
+ p = ptes[i].ext_pointer;
+ offset = extended_offset;
+ } else {
+ p = ptes[i].part_table;
+ offset = ptes[i].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);
+ ptes[i].changed = 1;
+}
+#endif
+
+static int
+warn_geometry(void)
+{
+ if (heads && sectors && cylinders)
+ return 0;
+
+ printf("Unknown value(s) for:");
+ if (!heads)
+ printf(" heads");
+ if (!sectors)
+ printf(" sectors");
+ if (!cylinders)
+ printf(" cylinders");
+ printf(
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ " (settable in the extra functions menu)"
+#endif
+ "\n");
+ return 1;
+}
+
+static void
+update_units(void)
+{
+ int cyl_units = heads * sectors;
+
+ if (display_in_cyl_units && cyl_units)
+ units_per_sector = cyl_units;
+ else
+ units_per_sector = 1; /* in sectors */
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static void
+warn_cylinders(void)
+{
+ if (LABEL_IS_DOS && cylinders > 1024 && !nowarn)
+ printf("\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., old versions of LILO)\n"
+"2) booting and partitioning software from other OSs\n"
+" (e.g., DOS FDISK, OS/2 FDISK)\n",
+ cylinders);
+}
+#endif
+
+static void
+read_extended(int ext)
+{
+ int i;
+ struct pte *pex;
+ struct partition *p, *q;
+
+ ext_index = ext;
+ pex = &ptes[ext];
+ pex->ext_pointer = pex->part_table;
+
+ p = pex->part_table;
+ if (!get_start_sect(p)) {
+ printf("Bad offset in primary extended partition\n");
+ return;
+ }
+
+ while (IS_EXTENDED(p->sys_ind)) {
+ struct pte *pe = &ptes[partitions];
+
+ if (partitions >= MAXIMUM_PARTS) {
+ /* This is not a Linux restriction, but
+ this program uses arrays of size MAXIMUM_PARTS.
+ Do not try to 'improve' this test. */
+ struct pte *pre = &ptes[partitions-1];
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ printf("Warning: deleting partitions after %d\n",
+ partitions);
+ pre->changed = 1;
+#endif
+ clear_partition(pre->ext_pointer);
+ return;
+ }
+
+ read_pte(pe, extended_offset + get_start_sect(p));
+
+ if (!extended_offset)
+ extended_offset = get_start_sect(p);
+
+ q = p = pt_offset(pe->sectorbuffer, 0);
+ for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
+ if (IS_EXTENDED(p->sys_ind)) {
+ if (pe->ext_pointer)
+ printf("Warning: extra link "
+ "pointer in partition table"
+ " %d\n", partitions + 1);
+ else
+ pe->ext_pointer = p;
+ } else if (p->sys_ind) {
+ if (pe->part_table)
+ printf("Warning: ignoring extra "
+ "data in partition table"
+ " %d\n", partitions + 1);
+ else
+ pe->part_table = p;
+ }
+ }
+
+ /* very strange code here... */
+ if (!pe->part_table) {
+ if (q != pe->ext_pointer)
+ pe->part_table = q;
+ else
+ pe->part_table = q + 1;
+ }
+ if (!pe->ext_pointer) {
+ if (q != pe->part_table)
+ pe->ext_pointer = q;
+ else
+ pe->ext_pointer = q + 1;
+ }
+
+ p = pe->ext_pointer;
+ partitions++;
+ }
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ /* remove empty links */
+ remove:
+ for (i = 4; i < partitions; i++) {
+ struct pte *pe = &ptes[i];
+
+ if (!get_nr_sects(pe->part_table)
+ && (partitions > 5 || ptes[4].part_table->sys_ind)
+ ) {
+ printf("Omitting empty partition (%d)\n", i+1);
+ delete_partition(i);
+ goto remove; /* numbering changed */
+ }
+ }
+#endif
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static void
+create_doslabel(void)
+{
+ int i;
+
+ printf(msg_building_new_label, "DOS disklabel");
+
+ current_label_type = label_dos;
+
+#if ENABLE_FEATURE_OSF_LABEL
+ possibly_osf_label = 0;
+#endif
+ partitions = 4;
+
+ for (i = 510-64; i < 510; i++)
+ MBRbuffer[i] = 0;
+ write_part_table_flag(MBRbuffer);
+ extended_offset = 0;
+ set_all_unchanged();
+ set_changed(0);
+ get_boot(create_empty_dos);
+}
+#endif /* FEATURE_FDISK_WRITABLE */
+
+static void
+get_sectorsize(void)
+{
+ if (!user_set_sector_size) {
+ int arg;
+ if (ioctl(fd, BLKSSZGET, &arg) == 0)
+ sector_size = arg;
+ if (sector_size != DEFAULT_SECTOR_SIZE)
+ printf("Note: sector size is %d (not %d)\n",
+ sector_size, DEFAULT_SECTOR_SIZE);
+ }
+}
+
+static void
+get_kernel_geometry(void)
+{
+ struct hd_geometry geometry;
+
+ if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
+ kern_heads = geometry.heads;
+ kern_sectors = geometry.sectors;
+ /* never use geometry.cylinders - it is truncated */
+ }
+}
+
+static void
+get_partition_table_geometry(void)
+{
+ const unsigned char *bufp = (const unsigned char *)MBRbuffer;
+ struct partition *p;
+ int i, h, s, hh, ss;
+ int first = 1;
+ int bad = 0;
+
+ if (!(valid_part_table_flag((char*)bufp)))
+ return;
+
+ hh = ss = 0;
+ for (i = 0; i < 4; i++) {
+ p = pt_offset(bufp, i);
+ if (p->sys_ind != 0) {
+ h = p->end_head + 1;
+ s = (p->end_sector & 077);
+ if (first) {
+ hh = h;
+ ss = s;
+ first = 0;
+ } else if (hh != h || ss != s)
+ bad = 1;
+ }
+ }
+
+ if (!first && !bad) {
+ pt_heads = hh;
+ pt_sectors = ss;
+ }
+}
+
+static void
+get_geometry(void)
+{
+ int sec_fac;
+ unsigned long long bytes; /* really u64 */
+
+ get_sectorsize();
+ sec_fac = sector_size / 512;
+#if ENABLE_FEATURE_SUN_LABEL
+ guess_device_type();
+#endif
+ heads = cylinders = sectors = 0;
+ kern_heads = kern_sectors = 0;
+ pt_heads = pt_sectors = 0;
+
+ get_kernel_geometry();
+ get_partition_table_geometry();
+
+ heads = user_heads ? user_heads :
+ pt_heads ? pt_heads :
+ kern_heads ? kern_heads : 255;
+ sectors = user_sectors ? user_sectors :
+ pt_sectors ? pt_sectors :
+ kern_sectors ? kern_sectors : 63;
+ if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
+ /* got bytes */
+ } else {
+ unsigned long longsectors;
+
+ if (ioctl(fd, BLKGETSIZE, &longsectors))
+ longsectors = 0;
+ bytes = ((unsigned long long) longsectors) << 9;
+ }
+
+ total_number_of_sectors = (bytes >> 9);
+
+ sector_offset = 1;
+ if (dos_compatible_flag)
+ sector_offset = sectors;
+
+ cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
+ if (!cylinders)
+ cylinders = user_cylinders;
+}
+
+/*
+ * Read MBR. Returns:
+ * -1: no 0xaa55 flag present (possibly entire disk BSD)
+ * 0: found or created label
+ * 1: I/O error
+ */
+static int
+get_boot(enum action what)
+{
+ int i;
+
+ partitions = 4;
+
+ for (i = 0; i < 4; i++) {
+ struct pte *pe = &ptes[i];
+
+ pe->part_table = pt_offset(MBRbuffer, i);
+ pe->ext_pointer = NULL;
+ pe->offset = 0;
+ pe->sectorbuffer = MBRbuffer;
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ pe->changed = (what == create_empty_dos);
+#endif
+ }
+
+#if ENABLE_FEATURE_SUN_LABEL
+ if (what == create_empty_sun && check_sun_label())
+ return 0;
+#endif
+
+ memset(MBRbuffer, 0, 512);
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ if (what == create_empty_dos)
+ goto got_dos_table; /* skip reading disk */
+
+ fd = open(disk_device, type_open);
+ if (fd < 0) {
+ fd = open(disk_device, O_RDONLY);
+ if (fd < 0) {
+ if (what == try_only)
+ return 1;
+ fdisk_fatal(unable_to_open);
+ } else
+ printf("You will not be able to write "
+ "the partition table\n");
+ }
+
+ if (512 != read(fd, MBRbuffer, 512)) {
+ if (what == try_only)
+ return 1;
+ fdisk_fatal(unable_to_read);
+ }
+#else
+ fd = open(disk_device, O_RDONLY);
+ if (fd < 0)
+ return 1;
+ if (512 != read(fd, MBRbuffer, 512))
+ return 1;
+#endif
+
+ get_geometry();
+
+ update_units();
+
+#if ENABLE_FEATURE_SUN_LABEL
+ if (check_sun_label())
+ return 0;
+#endif
+
+#if ENABLE_FEATURE_SGI_LABEL
+ if (check_sgi_label())
+ return 0;
+#endif
+
+#if ENABLE_FEATURE_AIX_LABEL
+ if (check_aix_label())
+ return 0;
+#endif
+
+#if ENABLE_FEATURE_OSF_LABEL
+ if (check_osf_label()) {
+ possibly_osf_label = 1;
+ if (!valid_part_table_flag(MBRbuffer)) {
+ current_label_type = label_osf;
+ return 0;
+ }
+ printf("This disk has both DOS and BSD magic.\n"
+ "Give the 'b' command to go to BSD mode.\n");
+ }
+#endif
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ got_dos_table:
+#endif
+
+ if (!valid_part_table_flag(MBRbuffer)) {
+#if !ENABLE_FEATURE_FDISK_WRITABLE
+ return -1;
+#else
+ switch (what) {
+ case fdisk:
+ printf("Device contains neither a valid DOS "
+ "partition table, nor Sun, SGI or OSF "
+ "disklabel\n");
+#ifdef __sparc__
+#if ENABLE_FEATURE_SUN_LABEL
+ create_sunlabel();
+#endif
+#else
+ create_doslabel();
+#endif
+ return 0;
+ case try_only:
+ return -1;
+ case create_empty_dos:
+#if ENABLE_FEATURE_SUN_LABEL
+ case create_empty_sun:
+#endif
+ break;
+ default:
+ bb_error_msg_and_die("internal error");
+ }
+#endif /* FEATURE_FDISK_WRITABLE */
+ }
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ warn_cylinders();
+#endif
+ warn_geometry();
+
+ for (i = 0; i < 4; i++) {
+ struct pte *pe = &ptes[i];
+
+ if (IS_EXTENDED(pe->part_table->sys_ind)) {
+ if (partitions != 4)
+ printf("Ignoring extra extended "
+ "partition %d\n", i + 1);
+ else
+ read_extended(i);
+ }
+ }
+
+ for (i = 3; i < partitions; i++) {
+ struct pte *pe = &ptes[i];
+
+ if (!valid_part_table_flag(pe->sectorbuffer)) {
+ printf("Warning: invalid flag 0x%02x,0x%02x of partition "
+ "table %d will be corrected by w(rite)\n",
+ pe->sectorbuffer[510],
+ pe->sectorbuffer[511],
+ i + 1);
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ pe->changed = 1;
+#endif
+ }
+ }
+
+ return 0;
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+/*
+ * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
+ * 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.
+ */
+static unsigned
+read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg)
+{
+ unsigned i;
+ int default_ok = 1;
+ const char *fmt = "%s (%u-%u, default %u): ";
+
+ if (dflt < low || dflt > high) {
+ fmt = "%s (%u-%u): ";
+ default_ok = 0;
+ }
+
+ while (1) {
+ int use_default = default_ok;
+
+ /* ask question and read answer */
+ do {
+ printf(fmt, mesg, low, high, dflt);
+ read_maybe_empty("");
+ } while (*line_ptr != '\n' && !isdigit(*line_ptr)
+ && *line_ptr != '-' && *line_ptr != '+');
+
+ if (*line_ptr == '+' || *line_ptr == '-') {
+ int minus = (*line_ptr == '-');
+ int absolute = 0;
+
+ i = atoi(line_ptr + 1);
+
+ while (isdigit(*++line_ptr))
+ use_default = 0;
+
+ switch (*line_ptr) {
+ case 'c':
+ case 'C':
+ if (!display_in_cyl_units)
+ i *= heads * sectors;
+ break;
+ case 'K':
+ absolute = 1024;
+ break;
+ case 'k':
+ absolute = 1000;
+ break;
+ case 'm':
+ case 'M':
+ absolute = 1000000;
+ break;
+ case 'g':
+ case 'G':
+ absolute = 1000000000;
+ break;
+ default:
+ break;
+ }
+ if (absolute) {
+ unsigned long long bytes;
+ unsigned long unit;
+
+ bytes = (unsigned long long) i * absolute;
+ unit = sector_size * units_per_sector;
+ bytes += unit/2; /* round */
+ bytes /= unit;
+ i = bytes;
+ }
+ if (minus)
+ i = -i;
+ i += base;
+ } else {
+ i = atoi(line_ptr);
+ while (isdigit(*line_ptr)) {
+ line_ptr++;
+ use_default = 0;
+ }
+ }
+ if (use_default) {
+ i = dflt;
+ printf("Using default value %u\n", i);
+ }
+ if (i >= low && i <= high)
+ break;
+ printf("Value is out of range\n");
+ }
+ return i;
+}
+
+static int
+get_partition(int warn, int max)
+{
+ struct pte *pe;
+ int i;
+
+ i = read_int(1, 0, max, 0, "Partition number") - 1;
+ pe = &ptes[i];
+
+ if (warn) {
+ if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
+ || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
+ || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
+ ) {
+ printf("Warning: partition %d has empty type\n", i+1);
+ }
+ }
+ return i;
+}
+
+static int
+get_existing_partition(int warn, int max)
+{
+ int pno = -1;
+ int i;
+
+ for (i = 0; i < max; i++) {
+ struct pte *pe = &ptes[i];
+ struct partition *p = pe->part_table;
+
+ if (p && !is_cleared_partition(p)) {
+ if (pno >= 0)
+ goto not_unique;
+ pno = i;
+ }
+ }
+ if (pno >= 0) {
+ printf("Selected partition %d\n", pno+1);
+ return pno;
+ }
+ printf("No partition is defined yet!\n");
+ return -1;
+
+ not_unique:
+ return get_partition(warn, max);
+}
+
+static int
+get_nonexisting_partition(int warn, int max)
+{
+ int pno = -1;
+ int i;
+
+ for (i = 0; i < max; i++) {
+ struct pte *pe = &ptes[i];
+ struct partition *p = pe->part_table;
+
+ if (p && is_cleared_partition(p)) {
+ if (pno >= 0)
+ goto not_unique;
+ pno = i;
+ }
+ }
+ if (pno >= 0) {
+ printf("Selected partition %d\n", pno+1);
+ return pno;
+ }
+ printf("All primary partitions have been defined already!\n");
+ return -1;
+
+ not_unique:
+ return get_partition(warn, max);
+}
+
+
+static void
+change_units(void)
+{
+ display_in_cyl_units = !display_in_cyl_units;
+ update_units();
+ printf("Changing display/entry units to %s\n",
+ str_units(PLURAL));
+}
+
+static void
+toggle_active(int i)
+{
+ struct pte *pe = &ptes[i];
+ struct partition *p = pe->part_table;
+
+ if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
+ printf("WARNING: Partition %d is an extended partition\n", i + 1);
+ p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
+ pe->changed = 1;
+}
+
+static void
+toggle_dos_compatibility_flag(void)
+{
+ dos_compatible_flag = ~dos_compatible_flag;
+ if (dos_compatible_flag) {
+ sector_offset = sectors;
+ printf("DOS Compatibility flag is set\n");
+ } else {
+ sector_offset = 1;
+ printf("DOS Compatibility flag is not set\n");
+ }
+}
+
+static void
+delete_partition(int i)
+{
+ struct pte *pe = &ptes[i];
+ struct partition *p = pe->part_table;
+ struct partition *q = pe->ext_pointer;
+
+/* Note that for the fifth partition (i == 4) we don't actually
+ * decrement partitions.
+ */
+
+ if (warn_geometry())
+ return; /* C/H/S not set */
+ pe->changed = 1;
+
+ if (LABEL_IS_SUN) {
+ sun_delete_partition(i);
+ return;
+ }
+ if (LABEL_IS_SGI) {
+ sgi_delete_partition(i);
+ return;
+ }
+
+ if (i < 4) {
+ if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
+ partitions = 4;
+ ptes[ext_index].ext_pointer = NULL;
+ extended_offset = 0;
+ }
+ clear_partition(p);
+ return;
+ }
+
+ if (!q->sys_ind && i > 4) {
+ /* the last one in the chain - just delete */
+ --partitions;
+ --i;
+ clear_partition(ptes[i].ext_pointer);
+ ptes[i].changed = 1;
+ } else {
+ /* not the last one - further ones will be moved down */
+ if (i > 4) {
+ /* delete this link in the chain */
+ p = ptes[i-1].ext_pointer;
+ *p = *q;
+ set_start_sect(p, get_start_sect(q));
+ set_nr_sects(p, get_nr_sects(q));
+ ptes[i-1].changed = 1;
+ } else if (partitions > 5) { /* 5 will be moved to 4 */
+ /* the first logical in a longer chain */
+ pe = &ptes[5];
+
+ if (pe->part_table) /* prevent SEGFAULT */
+ set_start_sect(pe->part_table,
+ get_partition_start(pe) -
+ extended_offset);
+ pe->offset = extended_offset;
+ pe->changed = 1;
+ }
+
+ if (partitions > 5) {
+ partitions--;
+ while (i < partitions) {
+ ptes[i] = ptes[i+1];
+ i++;
+ }
+ } else
+ /* the only logical: clear only */
+ clear_partition(ptes[i].part_table);
+ }
+}
+
+static void
+change_sysid(void)
+{
+ int i, sys, origsys;
+ struct partition *p;
+
+ /* If sgi_label then don't use get_existing_partition,
+ let the user select a partition, since get_existing_partition()
+ only works for Linux like partition tables. */
+ if (!LABEL_IS_SGI) {
+ i = get_existing_partition(0, partitions);
+ } else {
+ i = get_partition(0, partitions);
+ }
+ if (i == -1)
+ return;
+ p = ptes[i].part_table;
+ origsys = sys = get_sysid(i);
+
+ /* if changing types T to 0 is allowed, then
+ the reverse change must be allowed, too */
+ if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
+ printf("Partition %d does not exist yet!\n", i + 1);
+ return;
+ }
+ while (1) {
+ sys = read_hex(get_sys_types());
+
+ if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
+ printf("Type 0 means free space to many systems\n"
+ "(but not to Linux). Having partitions of\n"
+ "type 0 is probably unwise.\n");
+ /* break; */
+ }
+
+ if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
+ if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
+ printf("You cannot change a partition into"
+ " an extended one or vice versa\n");
+ break;
+ }
+ }
+
+ if (sys < 256) {
+#if ENABLE_FEATURE_SUN_LABEL
+ if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
+ printf("Consider leaving partition 3 "
+ "as Whole disk (5),\n"
+ "as SunOS/Solaris expects it and "
+ "even Linux likes it\n\n");
+#endif
+#if ENABLE_FEATURE_SGI_LABEL
+ if (LABEL_IS_SGI &&
+ (
+ (i == 10 && sys != SGI_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");
+ }
+#endif
+ if (sys == origsys)
+ break;
+ if (LABEL_IS_SUN) {
+ sun_change_sysid(i, sys);
+ } else if (LABEL_IS_SGI) {
+ sgi_change_sysid(i, sys);
+ } else
+ p->sys_ind = sys;
+
+ printf("Changed system type of partition %d "
+ "to %x (%s)\n", i + 1, sys,
+ partition_type(sys));
+ ptes[i].changed = 1;
+ if (is_dos_partition(origsys) ||
+ is_dos_partition(sys))
+ dos_changed = 1;
+ break;
+ }
+ }
+}
+#endif /* FEATURE_FDISK_WRITABLE */
+
+
+/* check_consistency() and linear2chs() 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
+linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *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(const struct partition *p, int partition)
+{
+ unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
+ unsigned pec, peh, pes; /* physical ending c, h, s */
+ unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
+ unsigned 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) */
+ linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
+
+/* compute logical ending (c, h, s) */
+ linear2chs(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);
+ }
+
+/* Ending on cylinder boundary? */
+ if (peh != (heads - 1) || pes != sectors) {
+ printf("Partition %i does not end on cylinder boundary\n",
+ partition + 1);
+ }
+}
+
+static void
+list_disk_geometry(void)
+{
+ long long bytes = (total_number_of_sectors << 9);
+ long megabytes = bytes/1000000;
+
+ if (megabytes < 10000)
+ printf("\nDisk %s: %ld MB, %lld bytes\n",
+ disk_device, megabytes, bytes);
+ else
+ printf("\nDisk %s: %ld.%ld GB, %lld bytes\n",
+ disk_device, megabytes/1000, (megabytes/100)%10, bytes);
+ printf("%d heads, %d sectors/track, %d cylinders",
+ heads, sectors, cylinders);
+ if (units_per_sector == 1)
+ printf(", total %llu sectors",
+ total_number_of_sectors / (sector_size/512));
+ printf("\nUnits = %s of %d * %d = %d bytes\n\n",
+ str_units(PLURAL),
+ units_per_sector, sector_size, units_per_sector * sector_size);
+}
+
+/*
+ * Check whether partition entries are ordered by their starting positions.
+ * Return 0 if OK. Return i if partition i should have been earlier.
+ * Two separate checks: primary and logical partitions.
+ */
+static int
+wrong_p_order(int *prev)
+{
+ const struct pte *pe;
+ const struct partition *p;
+ off_t last_p_start_pos = 0, p_start_pos;
+ int i, last_i = 0;
+
+ for (i = 0 ; i < partitions; i++) {
+ if (i == 4) {
+ last_i = 4;
+ last_p_start_pos = 0;
+ }
+ pe = &ptes[i];
+ if ((p = pe->part_table)->sys_ind) {
+ p_start_pos = get_partition_start(pe);
+
+ if (last_p_start_pos > p_start_pos) {
+ if (prev)
+ *prev = last_i;
+ return i;
+ }
+
+ last_p_start_pos = p_start_pos;
+ last_i = i;
+ }
+ }
+ return 0;
+}
+
+#if ENABLE_FEATURE_FDISK_ADVANCED
+/*
+ * Fix the chain of logicals.
+ * extended_offset is unchanged, the set of sectors used is unchanged
+ * The chain is sorted so that sectors increase, and so that
+ * starting sectors increase.
+ *
+ * After this it may still be that cfdisk doesnt like the table.
+ * (This is because cfdisk considers expanded parts, from link to
+ * end of partition, and these may still overlap.)
+ * Now
+ * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
+ * may help.
+ */
+static void
+fix_chain_of_logicals(void)
+{
+ int j, oj, ojj, sj, sjj;
+ struct partition *pj,*pjj,tmp;
+
+ /* Stage 1: sort sectors but leave sector of part 4 */
+ /* (Its sector is the global extended_offset.) */
+ stage1:
+ for (j = 5; j < partitions-1; j++) {
+ oj = ptes[j].offset;
+ ojj = ptes[j+1].offset;
+ if (oj > ojj) {
+ ptes[j].offset = ojj;
+ ptes[j+1].offset = oj;
+ pj = ptes[j].part_table;
+ set_start_sect(pj, get_start_sect(pj)+oj-ojj);
+ pjj = ptes[j+1].part_table;
+ set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
+ set_start_sect(ptes[j-1].ext_pointer,
+ ojj-extended_offset);
+ set_start_sect(ptes[j].ext_pointer,
+ oj-extended_offset);
+ goto stage1;
+ }
+ }
+
+ /* Stage 2: sort starting sectors */
+ stage2:
+ for (j = 4; j < partitions-1; j++) {
+ pj = ptes[j].part_table;
+ pjj = ptes[j+1].part_table;
+ sj = get_start_sect(pj);
+ sjj = get_start_sect(pjj);
+ oj = ptes[j].offset;
+ ojj = ptes[j+1].offset;
+ if (oj+sj > ojj+sjj) {
+ tmp = *pj;
+ *pj = *pjj;
+ *pjj = tmp;
+ set_start_sect(pj, ojj+sjj-oj);
+ set_start_sect(pjj, oj+sj-ojj);
+ goto stage2;
+ }
+ }
+
+ /* Probably something was changed */
+ for (j = 4; j < partitions; j++)
+ ptes[j].changed = 1;
+}
+
+
+static void
+fix_partition_table_order(void)
+{
+ struct pte *pei, *pek;
+ int i,k;
+
+ if (!wrong_p_order(NULL)) {
+ printf("Ordering is already correct\n\n");
+ return;
+ }
+
+ while ((i = wrong_p_order(&k)) != 0 && i < 4) {
+ /* partition i should have come earlier, move it */
+ /* We have to move data in the MBR */
+ struct partition *pi, *pk, *pe, pbuf;
+ pei = &ptes[i];
+ pek = &ptes[k];
+
+ pe = pei->ext_pointer;
+ pei->ext_pointer = pek->ext_pointer;
+ pek->ext_pointer = pe;
+
+ pi = pei->part_table;
+ pk = pek->part_table;
+
+ memmove(&pbuf, pi, sizeof(struct partition));
+ memmove(pi, pk, sizeof(struct partition));
+ memmove(pk, &pbuf, sizeof(struct partition));
+
+ pei->changed = pek->changed = 1;
+ }
+
+ if (i)
+ fix_chain_of_logicals();
+
+ printf("Done.\n");
+
+}
+#endif
+
+static void
+list_table(int xtra)
+{
+ const struct partition *p;
+ int i, w;
+
+ if (LABEL_IS_SUN) {
+ sun_list_table(xtra);
+ return;
+ }
+ if (LABEL_IS_SUN) {
+ sgi_list_table(xtra);
+ return;
+ }
+
+ list_disk_geometry();
+
+ if (LABEL_IS_OSF) {
+ xbsd_print_disklabel(xtra);
+ return;
+ }
+
+ /* 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. */
+ w = strlen(disk_device);
+ if (w && isdigit(disk_device[w-1]))
+ w++;
+ if (w < 5)
+ w = 5;
+
+ // 1 12345678901 12345678901 12345678901 12
+ printf("%*s Boot Start End Blocks Id System\n",
+ w+1, "Device");
+
+ for (i = 0; i < partitions; i++) {
+ const struct pte *pe = &ptes[i];
+ off_t psects;
+ off_t pblocks;
+ unsigned podd;
+
+ p = pe->part_table;
+ if (!p || is_cleared_partition(p))
+ continue;
+
+ psects = get_nr_sects(p);
+ pblocks = psects;
+ 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 %c %11llu %11llu %11llu%c %2x %s\n",
+ partname(disk_device, i+1, w+2),
+ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
+ ? '*' : '?',
+ (unsigned long long) cround(get_partition_start(pe)), /* start */
+ (unsigned long long) cround(get_partition_start(pe) + psects /* end */
+ - (psects ? 1 : 0)),
+ (unsigned long long) pblocks, podd ? '+' : ' ', /* odd flag on end */
+ p->sys_ind, /* type id */
+ partition_type(p->sys_ind)); /* type name */
+
+ check_consistency(p, i);
+ }
+
+ /* Is partition table in disk order? It need not be, but... */
+ /* partition table entries are not checked for correct order if this
+ is a sgi, sun or aix labeled disk... */
+ if (LABEL_IS_DOS && wrong_p_order(NULL)) {
+ /* FIXME */
+ printf("\nPartition table entries are not in disk order\n");
+ }
+}
+
+#if ENABLE_FEATURE_FDISK_ADVANCED
+static void
+x_list_table(int extend)
+{
+ const struct pte *pe;
+ const struct partition *p;
+ int i;
+
+ 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++) {
+ pe = &ptes[i];
+ p = (extend ? pe->ext_pointer : pe->part_table);
+ if (p != NULL) {
+ printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %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);
+ }
+ }
+}
+#endif
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static void
+fill_bounds(off_t *first, off_t *last)
+{
+ int i;
+ const struct pte *pe = &ptes[0];
+ const struct partition *p;
+
+ for (i = 0; i < partitions; pe++,i++) {
+ p = pe->part_table;
+ if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
+ first[i] = 0xffffffff;
+ last[i] = 0;
+ } else {
+ first[i] = get_partition_start(pe);
+ last[i] = first[i] + get_nr_sects(p) - 1;
+ }
+ }
+}
+
+static void
+check(int n, unsigned h, unsigned s, unsigned c, off_t start)
+{
+ off_t 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)
+ printf("Partition %d contains sector 0\n", n);
+ if (h >= heads)
+ printf("Partition %d: head %d greater than maximum %d\n",
+ n, h + 1, heads);
+ if (real_s >= sectors)
+ printf("Partition %d: sector %d greater than "
+ "maximum %d\n", n, s, sectors);
+ if (real_c >= cylinders)
+ printf("Partition %d: cylinder %"OFF_FMT"u greater than "
+ "maximum %d\n", n, real_c + 1, cylinders);
+ if (cylinders <= 1024 && start != total)
+ printf("Partition %d: previous sectors %"OFF_FMT"u disagrees with "
+ "total %"OFF_FMT"u\n", n, start, total);
+}
+
+static void
+verify(void)
+{
+ int i, j;
+ unsigned total = 1;
+ off_t first[partitions], last[partitions];
+ struct partition *p;
+
+ if (warn_geometry())
+ return;
+
+ if (LABEL_IS_SUN) {
+ verify_sun();
+ return;
+ }
+ if (LABEL_IS_SGI) {
+ verify_sgi(1);
+ return;
+ }
+
+ fill_bounds(first, last);
+ for (i = 0; i < partitions; i++) {
+ struct pte *pe = &ptes[i];
+
+ p = pe->part_table;
+ if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
+ check_consistency(p, i);
+ if (get_partition_start(pe) < 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) {
+ struct pte *pex = &ptes[ext_index];
+ off_t e_last = get_start_sect(pex->part_table) +
+ get_nr_sects(pex->part_table) - 1;
+
+ for (i = 4; i < partitions; i++) {
+ total++;
+ p = ptes[i].part_table;
+ 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 {
+ total = heads * sectors * cylinders - total;
+ if (total != 0)
+ printf("%d unallocated sectors\n", total);
+ }
+}
+
+static void
+add_partition(int n, int sys)
+{
+ char mesg[256]; /* 48 does not suffice in Japanese */
+ int i, num_read = 0;
+ struct partition *p = ptes[n].part_table;
+ struct partition *q = ptes[ext_index].part_table;
+ long long llimit;
+ off_t start, stop = 0, limit, temp,
+ first[partitions], last[partitions];
+
+ if (p && p->sys_ind) {
+ printf(msg_part_already_defined, n + 1);
+ return;
+ }
+ fill_bounds(first, last);
+ if (n < 4) {
+ start = sector_offset;
+ if (display_in_cyl_units || !total_number_of_sectors)
+ llimit = heads * sectors * cylinders - 1;
+ else
+ llimit = total_number_of_sectors - 1;
+ limit = llimit;
+ if (limit != llimit)
+ limit = 0x7fffffff;
+ 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 (display_in_cyl_units)
+ for (i = 0; i < partitions; i++)
+ first[i] = (cround(first[i]) - 1) * units_per_sector;
+
+ snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
+ do {
+ temp = start;
+ for (i = 0; i < partitions; i++) {
+ int lastplusoff;
+
+ if (start == ptes[i].offset)
+ 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+units_per_sector && num_read) {
+ printf("Sector %"OFF_FMT"d is already allocated\n", temp);
+ temp = start;
+ num_read = 0;
+ }
+ if (!num_read && start == temp) {
+ off_t saved_start;
+
+ saved_start = start;
+ start = read_int(cround(saved_start), cround(saved_start), cround(limit),
+ 0, mesg);
+ if (display_in_cyl_units) {
+ start = (start - 1) * units_per_sector;
+ if (start < saved_start) start = saved_start;
+ }
+ num_read = 1;
+ }
+ } while (start != temp || !num_read);
+ if (n > 4) { /* NOT for fifth partition */
+ struct pte *pe = &ptes[n];
+
+ pe->offset = start - sector_offset;
+ if (pe->offset == extended_offset) { /* must be corrected */
+ pe->offset++;
+ if (sector_offset == 1)
+ start++;
+ }
+ }
+
+ for (i = 0; i < partitions; i++) {
+ struct pte *pe = &ptes[i];
+
+ if (start < pe->offset && limit >= pe->offset)
+ limit = pe->offset - 1;
+ if (start < first[i] && limit >= first[i])
+ limit = first[i] - 1;
+ }
+ if (start > limit) {
+ printf("No free sectors available\n");
+ if (n > 4)
+ partitions--;
+ return;
+ }
+ if (cround(start) == cround(limit)) {
+ stop = limit;
+ } else {
+ snprintf(mesg, sizeof(mesg),
+ "Last %s or +size or +sizeM or +sizeK",
+ str_units(SINGULAR));
+ stop = read_int(cround(start), cround(limit), cround(limit),
+ cround(start), mesg);
+ if (display_in_cyl_units) {
+ stop = stop * units_per_sector - 1;
+ if (stop >limit)
+ stop = limit;
+ }
+ }
+
+ set_partition(n, 0, start, stop, sys);
+ if (n > 4)
+ set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
+
+ if (IS_EXTENDED(sys)) {
+ struct pte *pe4 = &ptes[4];
+ struct pte *pen = &ptes[n];
+
+ ext_index = n;
+ pen->ext_pointer = p;
+ pe4->offset = extended_offset = start;
+ pe4->sectorbuffer = xzalloc(sector_size);
+ pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
+ pe4->ext_pointer = pe4->part_table + 1;
+ pe4->changed = 1;
+ partitions = 5;
+ }
+}
+
+static void
+add_logical(void)
+{
+ if (partitions > 5 || ptes[4].part_table->sys_ind) {
+ struct pte *pe = &ptes[partitions];
+
+ pe->sectorbuffer = xzalloc(sector_size);
+ pe->part_table = pt_offset(pe->sectorbuffer, 0);
+ pe->ext_pointer = pe->part_table + 1;
+ pe->offset = 0;
+ pe->changed = 1;
+ partitions++;
+ }
+ add_partition(partitions - 1, LINUX_NATIVE);
+}
+
+static void
+new_partition(void)
+{
+ int i, free_primary = 0;
+
+ if (warn_geometry())
+ return;
+
+ if (LABEL_IS_SUN) {
+ add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
+ return;
+ }
+ if (LABEL_IS_SGI) {
+ sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
+ return;
+ }
+ if (LABEL_IS_AIX) {
+ printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
+"If you want to add DOS-type partitions, create a new empty DOS partition\n"
+"table first (use 'o'). This will destroy the present disk contents.\n");
+ return;
+ }
+
+ for (i = 0; i < 4; i++)
+ free_primary += !ptes[i].part_table->sys_ind;
+
+ if (!free_primary && partitions >= MAXIMUM_PARTS) {
+ printf("The maximum number of partitions has been created\n");
+ return;
+ }
+
+ 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[80];
+ snprintf(line, sizeof(line),
+ "Command action\n"
+ " %s\n"
+ " p primary partition (1-4)\n",
+ (extended_offset ?
+ "l logical (5 or over)" : "e extended"));
+ while (1) {
+ c = read_nonempty(line);
+ if (c == 'p' || c == 'P') {
+ i = get_nonexisting_partition(0, 4);
+ if (i >= 0)
+ add_partition(i, LINUX_NATIVE);
+ return;
+ }
+ if (c == 'l' && extended_offset) {
+ add_logical();
+ return;
+ }
+ if (c == 'e' && !extended_offset) {
+ i = get_nonexisting_partition(0, 4);
+ if (i >= 0)
+ add_partition(i, EXTENDED);
+ return;
+ }
+ printf("Invalid partition number "
+ "for type '%c'\n", c);
+ }
+ }
+}
+
+static void
+write_table(void)
+{
+ int i;
+
+ if (LABEL_IS_DOS) {
+ for (i = 0; i < 3; i++)
+ if (ptes[i].changed)
+ ptes[3].changed = 1;
+ for (i = 3; i < partitions; i++) {
+ struct pte *pe = &ptes[i];
+
+ if (pe->changed) {
+ write_part_table_flag(pe->sectorbuffer);
+ write_sector(pe->offset, pe->sectorbuffer);
+ }
+ }
+ }
+ else if (LABEL_IS_SGI) {
+ /* no test on change? the printf below might be mistaken */
+ sgi_write_table();
+ }
+ else if (LABEL_IS_SUN) {
+ int needw = 0;
+
+ for (i = 0; i < 8; i++)
+ if (ptes[i].changed)
+ needw = 1;
+ if (needw)
+ sun_write_table();
+ }
+
+ printf("The partition table has been altered!\n\n");
+ reread_partition_table(1);
+}
+
+static void
+reread_partition_table(int leave)
+{
+ int i;
+
+ printf("Calling ioctl() to re-read partition table\n");
+ sync();
+ /* sleep(2); Huh? */
+ i = ioctl(fd, BLKRRPART);
+#if 0
+ 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);
+ i = ioctl(fd, BLKRRPART);
+ }
+#endif
+
+ if (i) {
+ bb_perror_msg("WARNING: rereading partition table "
+ "failed, kernel still uses old table");
+ }
+
+#if 0
+ if (dos_changed)
+ 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");
+#endif
+
+ if (leave) {
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(fd);
+ exit(i != 0);
+ }
+}
+#endif /* FEATURE_FDISK_WRITABLE */
+
+#if ENABLE_FEATURE_FDISK_ADVANCED
+#define MAX_PER_LINE 16
+static void
+print_buffer(char *pbuffer)
+{
+ int i,l;
+
+ for (i = 0, l = 0; i < sector_size; i++, l++) {
+ if (l == 0)
+ printf("0x%03X:", i);
+ printf(" %02X", (unsigned char) pbuffer[i]);
+ if (l == MAX_PER_LINE - 1) {
+ puts("");
+ l = -1;
+ }
+ }
+ if (l > 0)
+ puts("");
+ puts("");
+}
+
+static void
+print_raw(void)
+{
+ int i;
+
+ printf("Device: %s\n", disk_device);
+ if (LABEL_IS_SGI || LABEL_IS_SUN)
+ print_buffer(MBRbuffer);
+ else {
+ for (i = 3; i < partitions; i++)
+ print_buffer(ptes[i].sectorbuffer);
+ }
+}
+
+static void
+move_begin(int i)
+{
+ struct pte *pe = &ptes[i];
+ struct partition *p = pe->part_table;
+ off_t 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_partition_start(pe);
+ new = read_int(first, first, first + get_nr_sects(p) - 1, first,
+ "New beginning of data") - pe->offset;
+
+ 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);
+ pe->changed = 1;
+ }
+}
+
+static void
+xselect(void)
+{
+ char c;
+
+ while (1) {
+ putchar('\n');
+ c = tolower(read_nonempty("Expert command (m for help): "));
+ switch (c) {
+ case 'a':
+ if (LABEL_IS_SUN)
+ sun_set_alt_cyl();
+ break;
+ case 'b':
+ if (LABEL_IS_DOS)
+ move_begin(get_partition(0, partitions));
+ break;
+ case 'c':
+ user_cylinders = cylinders =
+ read_int(1, cylinders, 1048576, 0,
+ "Number of cylinders");
+ if (LABEL_IS_SUN)
+ sun_set_ncyl(cylinders);
+ if (LABEL_IS_DOS)
+ warn_cylinders();
+ break;
+ case 'd':
+ print_raw();
+ break;
+ case 'e':
+ if (LABEL_IS_SGI)
+ sgi_set_xcyl();
+ else if (LABEL_IS_SUN)
+ sun_set_xcyl();
+ else if (LABEL_IS_DOS)
+ x_list_table(1);
+ break;
+ case 'f':
+ if (LABEL_IS_DOS)
+ fix_partition_table_order();
+ break;
+ case 'g':
+#if ENABLE_FEATURE_SGI_LABEL
+ create_sgilabel();
+#endif
+ break;
+ case 'h':
+ user_heads = heads = read_int(1, heads, 256, 0,
+ "Number of heads");
+ update_units();
+ break;
+ case 'i':
+ if (LABEL_IS_SUN)
+ sun_set_ilfact();
+ break;
+ case 'o':
+ if (LABEL_IS_SUN)
+ sun_set_rspeed();
+ break;
+ case 'p':
+ if (LABEL_IS_SUN)
+ list_table(1);
+ else
+ x_list_table(0);
+ break;
+ case 'q':
+ close(fd);
+ puts("");
+ exit(0);
+ case 'r':
+ return;
+ case 's':
+ user_sectors = sectors = read_int(1, sectors, 63, 0,
+ "Number of sectors");
+ if (dos_compatible_flag) {
+ sector_offset = sectors;
+ printf("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 (LABEL_IS_SUN)
+ sun_set_pcylcount();
+ break;
+ default:
+ xmenu();
+ }
+ }
+}
+#endif /* ADVANCED mode */
+
+static int
+is_ide_cdrom_or_tape(const char *device)
+{
+ FILE *procf;
+ char buf[100];
+ struct stat statbuf;
+ int is_ide = 0;
+
+ /* 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. */
+
+ if (strncmp("/dev/hd", device, 7))
+ return 0;
+
+ snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
+ procf = fopen(buf, "r");
+ if (procf != NULL && fgets(buf, sizeof(buf), procf))
+ is_ide = (!strncmp(buf, "cdrom", 5) ||
+ !strncmp(buf, "tape", 4));
+ else
+ /* Now when this proc file does not exist, skip the
+ device when it is read-only. */
+ if (stat(device, &statbuf) == 0)
+ is_ide = ((statbuf.st_mode & 0222) == 0);
+
+ if (procf)
+ fclose(procf);
+ return is_ide;
+}
+
+
+static void
+trydev(const char *device, int user_specified)
+{
+ int gb;
+
+ disk_device = device;
+ if (setjmp(listingbuf))
+ return;
+ if (!user_specified)
+ if (is_ide_cdrom_or_tape(device))
+ return;
+ fd = open(disk_device, type_open);
+ if (fd >= 0) {
+ gb = get_boot(try_only);
+ if (gb > 0) { /* I/O error */
+ close(fd);
+ } else if (gb < 0) { /* no DOS signature */
+ list_disk_geometry();
+ if (LABEL_IS_AIX) {
+ return;
+ }
+#if ENABLE_FEATURE_OSF_LABEL
+ if (bsd_trydev(device) < 0)
+#endif
+ printf("Disk %s doesn't contain a valid "
+ "partition table\n", device);
+ close(fd);
+ } else {
+ close(fd);
+ list_table(0);
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ if (!LABEL_IS_SUN && partitions > 4){
+ delete_partition(ext_index);
+ }
+#endif
+ }
+ } else {
+ /* Ignore other errors, since we try IDE
+ and SCSI hard disks which may not be
+ installed on the system. */
+ if (errno == EACCES) {
+ printf("Cannot open %s\n", device);
+ return;
+ }
+ }
+}
+
+/* for fdisk -l: try all things in /proc/partitions
+ that look like a partition name (do not end in a digit) */
+static void
+tryprocpt(void)
+{
+ FILE *procpt;
+ char line[100], ptname[100], devname[120], *s;
+ int ma, mi, sz;
+
+ procpt = fopen_or_warn("/proc/partitions", "r");
+
+ while (fgets(line, sizeof(line), procpt)) {
+ if (sscanf(line, " %d %d %d %[^\n ]",
+ &ma, &mi, &sz, ptname) != 4)
+ continue;
+ for (s = ptname; *s; s++);
+ if (isdigit(s[-1]))
+ continue;
+ sprintf(devname, "/dev/%s", ptname);
+ trydev(devname, 0);
+ }
+#if ENABLE_FEATURE_CLEAN_UP
+ fclose(procpt);
+#endif
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static void
+unknown_command(int c)
+{
+ printf("%c: unknown command\n", c);
+}
+#endif
+
+int fdisk_main(int argc, char **argv);
+int fdisk_main(int argc, char **argv)
+{
+ char *str_b, *str_C, *str_H, *str_S;
+ unsigned opt;
+ /*
+ * fdisk -v
+ * fdisk -l [-b sectorsize] [-u] device ...
+ * fdisk -s [partition] ...
+ * fdisk [-b sectorsize] [-u] device
+ *
+ * Options -C, -H, -S set the geometry.
+ */
+ enum {
+ OPT_b = 1 << 0,
+ OPT_C = 1 << 1,
+ OPT_H = 1 << 2,
+ OPT_l = 1 << 3,
+ OPT_S = 1 << 4,
+ OPT_u = 1 << 5,
+ OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
+ };
+
+ PTR_TO_GLOBALS = xzalloc(sizeof(G));
+
+ opt = getopt32(argc, argv, "b:C:H:lS:u" USE_FEATURE_FDISK_BLKSIZE("s"),
+ &str_b, &str_C, &str_H, &str_S);
+ argc -= optind;
+ argv += optind;
+ if (opt & OPT_b) { // -b
+ /* Ugly: this sector size is really per device,
+ so cannot be combined with multiple disks,
+ and the same goes for the C/H/S options.
+ */
+ sector_size = xatoi_u(str_b);
+ if (sector_size != 512 && sector_size != 1024 &&
+ sector_size != 2048)
+ bb_show_usage();
+ sector_offset = 2;
+ user_set_sector_size = 1;
+ }
+ if (opt & OPT_C) user_cylinders = xatoi_u(str_C); // -C
+ if (opt & OPT_H) { // -H
+ user_heads = xatoi_u(str_H);
+ if (user_heads <= 0 || user_heads >= 256)
+ user_heads = 0;
+ }
+ //if (opt & OPT_l) // -l
+ if (opt & OPT_S) { // -S
+ user_sectors = xatoi_u(str_S);
+ if (user_sectors <= 0 || user_sectors >= 64)
+ user_sectors = 0;
+ }
+ if (opt & OPT_u) display_in_cyl_units = 0; // -u
+ //if (opt & OPT_s) // -s
+
+ if (user_set_sector_size && argc != 1)
+ printf("Warning: the -b (set sector size) option should"
+ " be used with one specified device\n");
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ if (opt & OPT_l) {
+ nowarn = 1;
+#endif
+ type_open = O_RDONLY;
+ if (argc > 0) {
+ int k;
+#if defined(__GNUC__)
+ /* avoid gcc warning:
+ variable `k' might be clobbered by `longjmp' */
+ (void)&k;
+#endif
+ listing = 1;
+ for (k = 0; k < argc; k++)
+ trydev(argv[k], 1);
+ } else {
+ /* we no longer have default device names */
+ /* but, we can use /proc/partitions instead */
+ tryprocpt();
+ }
+ return 0;
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ }
+#endif
+
+#if ENABLE_FEATURE_FDISK_BLKSIZE
+ if (opt & OPT_s) {
+ long size;
+ int j;
+
+ nowarn = 1;
+ type_open = O_RDONLY;
+
+ if (argc <= 0)
+ bb_show_usage();
+
+ for (j = 0; j < argc; j++) {
+ disk_device = argv[j];
+ fd = open(disk_device, type_open);
+ if (fd < 0)
+ fdisk_fatal(unable_to_open);
+ if (ioctl(fd, BLKGETSIZE, &size))
+ fdisk_fatal(ioctl_error);
+ close(fd);
+ if (argc == 1)
+ printf("%ld\n", size/2);
+ else
+ printf("%s: %ld\n", argv[j], size/2);
+ }
+ return 0;
+ }
+#endif
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ if (argc != 1)
+ bb_show_usage();
+
+ disk_device = argv[0];
+ get_boot(fdisk);
+
+ if (LABEL_IS_OSF) {
+ /* OSF label, and no DOS label */
+ printf("Detected an OSF/1 disklabel on %s, entering "
+ "disklabel mode\n", disk_device);
+ bsd_select();
+ /*Why do we do this? It seems to be counter-intuitive*/
+ current_label_type = label_dos;
+ /* If we return we may want to make an empty DOS label? */
+ }
+
+ while (1) {
+ int c;
+ putchar('\n');
+ c = tolower(read_nonempty("Command (m for help): "));
+ switch (c) {
+ case 'a':
+ if (LABEL_IS_DOS)
+ toggle_active(get_partition(1, partitions));
+ else if (LABEL_IS_SUN)
+ toggle_sunflags(get_partition(1, partitions),
+ 0x01);
+ else if (LABEL_IS_SGI)
+ sgi_set_bootpartition(
+ get_partition(1, partitions));
+ else
+ unknown_command(c);
+ break;
+ case 'b':
+ if (LABEL_IS_SGI) {
+ printf("\nThe current boot file is: %s\n",
+ sgi_get_bootfile());
+ if (read_maybe_empty("Please enter the name of the "
+ "new boot file: ") == '\n')
+ printf("Boot file unchanged\n");
+ else
+ sgi_set_bootfile(line_ptr);
+ }
+#if ENABLE_FEATURE_OSF_LABEL
+ else
+ bsd_select();
+#endif
+ break;
+ case 'c':
+ if (LABEL_IS_DOS)
+ toggle_dos_compatibility_flag();
+ else if (LABEL_IS_SUN)
+ toggle_sunflags(get_partition(1, partitions),
+ 0x10);
+ else if (LABEL_IS_SGI)
+ sgi_set_swappartition(
+ get_partition(1, partitions));
+ else
+ unknown_command(c);
+ break;
+ case 'd':
+ {
+ int j;
+ /* If sgi_label then don't use get_existing_partition,
+ let the user select a partition, since
+ get_existing_partition() only works for Linux-like
+ partition tables */
+ if (!LABEL_IS_SGI) {
+ j = get_existing_partition(1, partitions);
+ } else {
+ j = get_partition(1, partitions);
+ }
+ if (j >= 0)
+ delete_partition(j);
+ }
+ break;
+ case 'i':
+ if (LABEL_IS_SGI)
+ create_sgiinfo();
+ else
+ unknown_command(c);
+ case 'l':
+ list_types(get_sys_types());
+ break;
+ case 'm':
+ menu();
+ break;
+ case 'n':
+ new_partition();
+ break;
+ case 'o':
+ create_doslabel();
+ break;
+ case 'p':
+ list_table(0);
+ break;
+ case 'q':
+ close(fd);
+ puts("");
+ return 0;
+ case 's':
+#if ENABLE_FEATURE_SUN_LABEL
+ create_sunlabel();
+#endif
+ break;
+ case 't':
+ change_sysid();
+ break;
+ case 'u':
+ change_units();
+ break;
+ case 'v':
+ verify();
+ break;
+ case 'w':
+ write_table(); /* does not return */
+ break;
+#if ENABLE_FEATURE_FDISK_ADVANCED
+ case 'x':
+ if (LABEL_IS_SGI) {
+ printf("\n\tSorry, no experts menu for SGI "
+ "partition tables available\n\n");
+ } else
+ xselect();
+ break;
+#endif
+ default:
+ unknown_command(c);
+ menu();
+ }
+ }
+ return 0;
+#endif /* FEATURE_FDISK_WRITABLE */
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/fdisk_aix.c b/i/pc104/initrd/conf/busybox/util-linux/fdisk_aix.c
new file mode 100644
index 0000000..8095fc4
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/fdisk_aix.c
@@ -0,0 +1,73 @@
+#if ENABLE_FEATURE_AIX_LABEL
+/*
+ * 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
+
+#define aixlabel ((aix_partition *)MBRbuffer)
+
+
+/*
+ Changes:
+ * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ * Internationalization
+ *
+ * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
+ * Some fixes
+*/
+
+static int aix_other_endian;
+static short aix_volumes = 1;
+
+/*
+ * only dealing with free blocks here
+ */
+
+static void
+aix_info(void)
+{
+ puts("\n"
+"There is a valid AIX label on this disk.\n"
+"Unfortunately Linux cannot handle these disks at the moment.\n"
+"Nevertheless some advice:\n"
+"1. fdisk will destroy its contents on write.\n"
+"2. Be sure that this disk is NOT a still vital part of a volume group.\n"
+" (Otherwise you may erase the other disks as well, if unmirrored.)\n"
+"3. Before deleting this physical volume be sure to remove the disk\n"
+" logically from your AIX machine. (Otherwise you become an AIXpert).\n"
+ );
+}
+
+static int
+check_aix_label(void)
+{
+ if (aixlabel->magic != AIX_LABEL_MAGIC &&
+ aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
+ current_label_type = 0;
+ aix_other_endian = 0;
+ return 0;
+ }
+ aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
+ update_units();
+ current_label_type = label_aix;
+ partitions = 1016;
+ aix_volumes = 15;
+ aix_info();
+ /*aix_nolabel();*/ /* %% */
+ /*aix_label = 1;*/ /* %% */
+ return 1;
+}
+#endif /* AIX_LABEL */
diff --git a/i/pc104/initrd/conf/busybox/util-linux/fdisk_osf.c b/i/pc104/initrd/conf/busybox/util-linux/fdisk_osf.c
new file mode 100644
index 0000000..afb8459
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/fdisk_osf.c
@@ -0,0 +1,1063 @@
+#if ENABLE_FEATURE_OSF_LABEL
+/*
+ * 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 acknowledgment:
+ * 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.
+ */
+
+
+#ifndef BSD_DISKMAGIC
+#define BSD_DISKMAGIC ((uint32_t) 0x82564557)
+#endif
+
+#ifndef BSD_MAXPARTITIONS
+#define BSD_MAXPARTITIONS 16
+#endif
+
+#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
+
+#if defined(i386) || defined(__sparc__) || defined(__arm__) \
+ || defined(__m68k__) || defined(__mips__) || defined(__s390__) \
+ || defined(__sh__) || defined(__x86_64__)
+#define BSD_LABELSECTOR 1
+#define BSD_LABELOFFSET 0
+#elif defined(__alpha__) || defined(__powerpc__) || defined(__ia64__) \
+ || defined(__hppa__)
+#define BSD_LABELSECTOR 0
+#define BSD_LABELOFFSET 64
+#elif defined(__s390__) || defined(__s390x__)
+#define BSD_LABELSECTOR 1
+#define BSD_LABELOFFSET 0
+#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 {
+ uint32_t d_magic; /* the magic number */
+ int16_t d_type; /* drive type */
+ int16_t d_subtype; /* controller/d_type specific */
+ char d_typename[16]; /* type name, e.g. "eagle" */
+ char d_packname[16]; /* pack identifier */
+ /* disk geometry: */
+ uint32_t d_secsize; /* # of bytes per sector */
+ uint32_t d_nsectors; /* # of data sectors per track */
+ uint32_t d_ntracks; /* # of tracks per cylinder */
+ uint32_t d_ncylinders; /* # of data cylinders per unit */
+ uint32_t d_secpercyl; /* # of data sectors per cylinder */
+ uint32_t 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.
+ */
+ uint16_t d_sparespertrack; /* # of spare sectors per track */
+ uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
+ /*
+ * Alternate cylinders include maintenance, replacement,
+ * configuration description areas, etc.
+ */
+ uint32_t 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.
+ */
+ uint16_t d_rpm; /* rotational speed */
+ uint16_t d_interleave; /* hardware sector interleave */
+ uint16_t d_trackskew; /* sector 0 skew, per track */
+ uint16_t d_cylskew; /* sector 0 skew, per cylinder */
+ uint32_t d_headswitch; /* head switch time, usec */
+ uint32_t d_trkseek; /* track-to-track seek, usec */
+ uint32_t d_flags; /* generic flags */
+#define NDDATA 5
+ uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
+#define NSPARE 5
+ uint32_t d_spare[NSPARE]; /* reserved for future use */
+ uint32_t d_magic2; /* the magic number (again) */
+ uint16_t d_checksum; /* xor of data incl. partitions */
+ /* filesystem and partition information: */
+ uint16_t d_npartitions; /* number of partitions in following */
+ uint32_t d_bbsize; /* size of boot area at sn0, bytes */
+ uint32_t d_sbsize; /* max size of fs superblock, bytes */
+ struct xbsd_partition { /* the partition table */
+ uint32_t p_size; /* number of sectors in partition */
+ uint32_t p_offset; /* starting sector */
+ uint32_t p_fsize; /* filesystem basic fragment size */
+ uint8_t p_fstype; /* filesystem type, see below */
+ uint8_t p_frag; /* filesystem fragments per block */
+ uint16_t 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 */
+
+static const char * const 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)
+
+/*
+ * 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 */
+#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
+
+/* this is annoying, but it's also the way it is :-( */
+#ifdef __alpha__
+#define BSD_FS_EXT2 8 /* ext2 file system */
+#else
+#define BSD_FS_MSDOS 8 /* MS-DOS file system */
+#endif
+
+static const char *const xbsd_fstypes[] = {
+ "\x00" "unused", /* BSD_FS_UNUSED */
+ "\x01" "swap", /* BSD_FS_SWAP */
+ "\x02" "Version 6", /* BSD_FS_V6 */
+ "\x03" "Version 7", /* BSD_FS_V7 */
+ "\x04" "System V", /* BSD_FS_SYSV */
+ "\x05" "4.1BSD", /* BSD_FS_V71K */
+ "\x06" "Eighth Edition", /* BSD_FS_V8 */
+ "\x07" "4.2BSD", /* BSD_FS_BSDFFS */
+#ifdef __alpha__
+ "\x08" "ext2", /* BSD_FS_EXT2 */
+#else
+ "\x08" "MS-DOS", /* BSD_FS_MSDOS */
+#endif
+ "\x09" "4.4LFS", /* BSD_FS_BSDLFS */
+ "\x0a" "unknown", /* BSD_FS_OTHER */
+ "\x0b" "HPFS", /* BSD_FS_HPFS */
+ "\x0c" "ISO-9660", /* BSD_FS_ISO9660 */
+ "\x0d" "boot", /* BSD_FS_BOOT */
+ "\x0e" "ADOS", /* BSD_FS_ADOS */
+ "\x0f" "HFS", /* BSD_FS_HFS */
+ "\x10" "AdvFS", /* BSD_FS_ADVFS */
+ NULL
+};
+#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
+
+
+/*
+ * 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 */
+
+/*
+ Changes:
+ 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
+
+ 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
+ support for OSF/1 disklabels on Alpha.
+ Also fixed unaligned accesses in alpha_bootblock_checksum()
+*/
+
+static int possibly_osf_label;
+
+#define FREEBSD_PARTITION 0xa5
+#define NETBSD_PARTITION 0xa9
+
+static void xbsd_delete_part(void);
+static void xbsd_new_part(void);
+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 uint16_t xbsd_dkcksum(struct xbsd_disklabel *lp);
+static int xbsd_initlabel(struct partition *p);
+static int xbsd_readlabel(struct partition *p);
+static int xbsd_writelabel(struct partition *p);
+
+#if defined(__alpha__)
+static void alpha_bootblock_checksum(char *boot);
+#endif
+
+#if !defined(__alpha__)
+static int xbsd_translate_fstype(int linux_type);
+static void xbsd_link_part(void);
+static struct partition *xbsd_part;
+static int xbsd_part_index;
+#endif
+
+
+/* Group big globals data and allocate it in one go */
+struct bsd_globals {
+/* We access this through a uint64_t * when checksumming */
+/* hopefully xmalloc gives us required alignment */
+ char disklabelbuffer[BSD_BBSIZE];
+ struct xbsd_disklabel xbsd_dlabel;
+};
+
+static struct bsd_globals *bsd_globals_ptr;
+
+#define disklabelbuffer (bsd_globals_ptr->disklabelbuffer)
+#define xbsd_dlabel (bsd_globals_ptr->xbsd_dlabel)
+
+
+/* Code */
+
+#define bsd_cround(n) \
+ (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
+
+/*
+ * Test whether the whole disk has BSD disk label magic.
+ *
+ * Note: often reformatting with DOS-type label leaves the BSD magic,
+ * so this does not mean that there is a BSD disk label.
+ */
+static int
+check_osf_label(void)
+{
+ if (xbsd_readlabel(NULL) == 0)
+ return 0;
+ return 1;
+}
+
+static int
+bsd_trydev(const char * dev)
+{
+ if (xbsd_readlabel(NULL) == 0)
+ return -1;
+ printf("\nBSD label for device: %s\n", dev);
+ xbsd_print_disklabel(0);
+ return 0;
+}
+
+static void
+bsd_menu(void)
+{
+ puts("Command Action");
+ puts("d\tdelete a BSD partition");
+ puts("e\tedit drive data");
+ puts("i\tinstall bootstrap");
+ puts("l\tlist known filesystem types");
+ puts("n\tadd a new BSD partition");
+ puts("p\tprint BSD partition table");
+ puts("q\tquit without saving changes");
+ puts("r\treturn to main menu");
+ puts("s\tshow complete disklabel");
+ puts("t\tchange a partition's filesystem id");
+ puts("u\tchange units (cylinders/sectors)");
+ puts("w\twrite disklabel to disk");
+#if !defined(__alpha__)
+ puts("x\tlink BSD partition to non-BSD partition");
+#endif
+}
+
+#if !defined(__alpha__)
+static int
+hidden(int type)
+{
+ return type ^ 0x10;
+}
+
+static int
+is_bsd_partition_type(int type)
+{
+ return (type == FREEBSD_PARTITION ||
+ type == hidden(FREEBSD_PARTITION) ||
+ type == NETBSD_PARTITION ||
+ type == hidden(NETBSD_PARTITION));
+}
+#endif
+
+static void
+bsd_select(void)
+{
+#if !defined(__alpha__)
+ int t, ss;
+ struct partition *p;
+
+ for (t = 0; t < 4; t++) {
+ p = get_part_table(t);
+ if (p && is_bsd_partition_type(p->sys_ind)) {
+ xbsd_part = p;
+ xbsd_part_index = t;
+ ss = get_start_sect(xbsd_part);
+ if (ss == 0) {
+ printf("Partition %s has invalid starting sector 0\n",
+ partname(disk_device, t+1, 0));
+ return;
+ }
+ printf("Reading disklabel of %s at sector %d\n",
+ partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
+ if (xbsd_readlabel(xbsd_part) == 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) == 0)
+ if (xbsd_create_disklabel() == 0)
+ exit(EXIT_SUCCESS);
+
+#endif
+
+ while (1) {
+ putchar('\n');
+ switch (tolower(read_nonempty("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 'r':
+ return;
+ case 's':
+ xbsd_print_disklabel(1);
+ break;
+ case 't':
+ xbsd_change_fstype();
+ break;
+ case 'u':
+ change_units();
+ break;
+ case 'w':
+ xbsd_write_disklabel();
+ break;
+#if !defined(__alpha__)
+ case 'x':
+ xbsd_link_part();
+ break;
+#endif
+ default:
+ bsd_menu();
+ 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)
+{
+ off_t begin, end;
+ char mesg[256];
+ int i;
+
+ if (!xbsd_check_new_partition(&i))
+ return;
+
+#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__hppa__)
+ begin = get_start_sect(xbsd_part);
+ end = begin + get_nr_sects(xbsd_part) - 1;
+#else
+ begin = 0;
+ end = xbsd_dlabel.d_secperunit - 1;
+#endif
+
+ snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
+ begin = read_int(bsd_cround(begin), bsd_cround(begin), bsd_cround(end),
+ 0, mesg);
+
+ if (display_in_cyl_units)
+ begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
+
+ snprintf(mesg, sizeof(mesg), "Last %s or +size or +sizeM or +sizeK",
+ str_units(SINGULAR));
+ end = read_int(bsd_cround(begin), bsd_cround(end), bsd_cround(end),
+ bsd_cround(begin), mesg);
+
+ if (display_in_cyl_units)
+ end = end * xbsd_dlabel.d_secpercyl - 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;
+ int i, j;
+
+ if (show_all) {
+#if defined(__alpha__)
+ printf("# %s:\n", disk_device);
+#else
+ printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
+#endif
+ if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
+ printf("type: %s\n", xbsd_dktypenames[lp->d_type]);
+ else
+ printf("type: %d\n", lp->d_type);
+ printf("disk: %.*s\n", (int) sizeof(lp->d_typename), lp->d_typename);
+ printf("label: %.*s\n", (int) sizeof(lp->d_packname), lp->d_packname);
+ printf("flags:");
+ if (lp->d_flags & BSD_D_REMOVABLE)
+ printf(" removable");
+ if (lp->d_flags & BSD_D_ECC)
+ printf(" ecc");
+ if (lp->d_flags & BSD_D_BADSECT)
+ printf(" badsect");
+ puts("");
+ /* On various machines the fields of *lp are short/int/long */
+ /* In order to avoid problems, we cast them all to long. */
+ printf("bytes/sector: %ld\n", (long) lp->d_secsize);
+ printf("sectors/track: %ld\n", (long) lp->d_nsectors);
+ printf("tracks/cylinder: %ld\n", (long) lp->d_ntracks);
+ printf("sectors/cylinder: %ld\n", (long) lp->d_secpercyl);
+ printf("cylinders: %ld\n", (long) lp->d_ncylinders);
+ printf("rpm: %d\n", lp->d_rpm);
+ printf("interleave: %d\n", lp->d_interleave);
+ printf("trackskew: %d\n", lp->d_trackskew);
+ printf("cylinderskew: %d\n", lp->d_cylskew);
+ printf("headswitch: %ld\t\t# milliseconds\n",
+ (long) lp->d_headswitch);
+ printf("track-to-track seek: %ld\t# milliseconds\n",
+ (long) lp->d_trkseek);
+ printf("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++)
+ printf("%ld ", (long) lp->d_drivedata[j]);
+ }
+ printf("\n%d partitions:\n", lp->d_npartitions);
+ printf("# start end size fstype [fsize bsize cpg]\n");
+ pp = lp->d_partitions;
+ for (i = 0; i < lp->d_npartitions; i++, pp++) {
+ if (pp->p_size) {
+ if (display_in_cyl_units && lp->d_secpercyl) {
+ printf(" %c: %8ld%c %8ld%c %8ld%c ",
+ 'a' + i,
+ (long) pp->p_offset / lp->d_secpercyl + 1,
+ (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
+ (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl,
+ ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
+ (long) pp->p_size / lp->d_secpercyl,
+ (pp->p_size % lp->d_secpercyl) ? '*' : ' '
+ );
+ } else {
+ printf(" %c: %8ld %8ld %8ld ",
+ 'a' + i,
+ (long) pp->p_offset,
+ (long) pp->p_offset + pp->p_size - 1,
+ (long) pp->p_size
+ );
+ }
+
+ if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
+ printf("%8.8s", xbsd_fstypes[pp->p_fstype]);
+ else
+ printf("%8x", pp->p_fstype);
+
+ switch (pp->p_fstype) {
+ case BSD_FS_UNUSED:
+ printf(" %5ld %5ld %5.5s ",
+ (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
+ break;
+ case BSD_FS_BSDFFS:
+ printf(" %5ld %5ld %5d ",
+ (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, pp->p_cpg);
+ break;
+ default:
+ printf("%22.22s", "");
+ break;
+ }
+ puts("");
+ }
+ }
+}
+
+static void
+xbsd_write_disklabel(void)
+{
+#if defined(__alpha__)
+ printf("Writing disklabel to %s\n", disk_device);
+ xbsd_writelabel(NULL);
+#else
+ printf("Writing disklabel to %s\n",
+ partname(disk_device, xbsd_part_index + 1, 0));
+ xbsd_writelabel(xbsd_part);
+#endif
+ reread_partition_table(0); /* no exit yet */
+}
+
+static int
+xbsd_create_disklabel(void)
+{
+ char c;
+
+#if defined(__alpha__)
+ printf("%s contains no disklabel\n", disk_device);
+#else
+ printf("%s contains no disklabel\n",
+ partname(disk_device, xbsd_part_index + 1, 0));
+#endif
+
+ while (1) {
+ c = read_nonempty("Do you want to create a disklabel? (y/n) ");
+ if (c == 'y' || c == 'Y') {
+ if (xbsd_initlabel(
+#if defined(__alpha__) || defined(__powerpc__) || defined(__hppa__) || \
+ defined(__s390__) || defined(__s390x__)
+ NULL
+#else
+ xbsd_part
+#endif
+ ) == 1) {
+ xbsd_print_disklabel(1);
+ return 1;
+ } else
+ return 0;
+ } else if (c == 'n')
+ return 0;
+ }
+}
+
+static int
+edit_int(int def, const char *mesg)
+{
+ mesg = xasprintf("%s (%d): ", mesg, def);
+ do {
+ if (!read_line(mesg))
+ goto ret;
+ } while (!isdigit(*line_ptr));
+ def = atoi(line_ptr);
+ ret:
+ free((char*)mesg);
+ return def;
+}
+
+static void
+xbsd_edit_disklabel(void)
+{
+ struct xbsd_disklabel *d;
+
+ d = &xbsd_dlabel;
+
+#if defined(__alpha__) || defined(__ia64__)
+ d->d_secsize = edit_int(d->d_secsize , "bytes/sector");
+ d->d_nsectors = edit_int(d->d_nsectors , "sectors/track");
+ d->d_ntracks = edit_int(d->d_ntracks , "tracks/cylinder");
+ d->d_ncylinders = edit_int(d->d_ncylinders , "cylinders");
+#endif
+
+ /* d->d_secpercyl can be != d->d_nsectors * d->d_ntracks */
+ while (1) {
+ d->d_secpercyl = edit_int(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 = edit_int(d->d_rpm , "rpm");
+ d->d_interleave = edit_int(d->d_interleave, "interleave");
+ d->d_trackskew = edit_int(d->d_trackskew , "trackskew");
+ d->d_cylskew = edit_int(d->d_cylskew , "cylinderskew");
+ d->d_headswitch = edit_int(d->d_headswitch, "headswitch");
+ d->d_trkseek = edit_int(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 fdb;
+
+ fdb = open(path, O_RDONLY);
+ if (fdb < 0) {
+ perror(path);
+ return 0;
+ }
+ if (read(fdb, ptr, size) < 0) {
+ perror(path);
+ close(fdb);
+ return 0;
+ }
+ printf(" ... %s\n", path);
+ close(fdb);
+ return 1;
+}
+
+static void
+sync_disks(void)
+{
+ printf("Syncing disks\n");
+ sync();
+ /* sleep(4); What? */
+}
+
+static void
+xbsd_write_bootstrap(void)
+{
+ char path[MAXPATHLEN];
+ const char *bootdir = BSD_LINUX_BOOTDIR;
+ const 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";
+
+ snprintf(path, sizeof(path), "Bootstrap: %sboot -> boot%s (%s): ",
+ dkbasename, dkbasename, dkbasename);
+ if (read_line(path)) {
+ dkbasename = line_ptr;
+ }
+ snprintf(path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
+ if (!xbsd_get_bootstrap(path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
+ return;
+
+/* We need a backup of the disklabel (xbsd_dlabel might have changed). */
+ d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
+ memmove(&dl, d, sizeof(struct xbsd_disklabel));
+
+/* The disklabel will be overwritten by 0's from bootxx anyway */
+ memset(d, 0, sizeof(struct xbsd_disklabel));
+
+ snprintf(path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
+ if (!xbsd_get_bootstrap(path, &disklabelbuffer[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) {
+ printf("Bootstrap overlaps with disk label!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ memmove(d, &dl, sizeof(struct xbsd_disklabel));
+
+#if defined(__powerpc__) || defined(__hppa__)
+ sector = 0;
+#elif defined(__alpha__)
+ sector = 0;
+ alpha_bootblock_checksum(disklabelbuffer);
+#else
+ sector = get_start_sect(xbsd_part);
+#endif
+
+ if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
+ fdisk_fatal(unable_to_seek);
+ if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
+ fdisk_fatal(unable_to_write);
+
+#if defined(__alpha__)
+ printf("Bootstrap installed on %s\n", disk_device);
+#else
+ printf("Bootstrap installed on %s\n",
+ partname(disk_device, xbsd_part_index+1, 0));
+#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[sizeof("Partition (a-%c): ") + 16];
+ char l;
+
+ snprintf(prompt, sizeof(prompt), "Partition (a-%c): ", 'a' + max - 1);
+ do
+ l = tolower(read_nonempty(prompt));
+ while (l < 'a' || l > 'a' + max - 1);
+ return l - 'a';
+}
+
+static int
+xbsd_check_new_partition(int *i)
+{
+ /* room for more? various BSD flavours have different maxima */
+ if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
+ int t;
+
+ for (t = 0; t < BSD_MAXPARTITIONS; t++)
+ if (xbsd_dlabel.d_partitions[t].p_size == 0)
+ break;
+
+ if (t == BSD_MAXPARTITIONS) {
+ printf("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) {
+ printf("This partition already exists\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static void
+xbsd_list_types(void)
+{
+ list_types(xbsd_fstypes);
+}
+
+static uint16_t
+xbsd_dkcksum(struct xbsd_disklabel *lp)
+{
+ uint16_t *start, *end;
+ uint16_t sum = 0;
+
+ start = (uint16_t *) lp;
+ end = (uint16_t *) &lp->d_partitions[lp->d_npartitions];
+ while (start < end)
+ sum ^= *start++;
+ return sum;
+}
+
+static int
+xbsd_initlabel(struct partition *p)
+{
+ struct xbsd_disklabel *d = &xbsd_dlabel;
+ struct xbsd_partition *pp;
+
+ get_geometry();
+ memset(d, 0, 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 !defined(__alpha__)
+ d->d_flags = BSD_D_DOSPART;
+#else
+ d->d_flags = 0;
+#endif
+ d->d_secsize = SECTOR_SIZE; /* bytes/sector */
+ d->d_nsectors = sectors; /* sectors/track */
+ d->d_ntracks = heads; /* tracks/cylinder (heads) */
+ d->d_ncylinders = cylinders;
+ d->d_secpercyl = sectors * heads; /* sectors/cylinder */
+ if (d->d_secpercyl == 0)
+ d->d_secpercyl = 1; /* avoid segfaults */
+ 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(__alpha__)
+ d->d_npartitions = 4;
+ pp = &d->d_partitions[2]; /* Partition C should be 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 whole disk */
+
+ pp->p_offset = 0;
+ pp->p_size = d->d_secperunit;
+ pp->p_fstype = BSD_FS_UNUSED;
+#else
+ 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;
+}
+
+/*
+ * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
+ * If it has the right magic, return 1.
+ */
+static int
+xbsd_readlabel(struct partition *p)
+{
+ struct xbsd_disklabel *d;
+ int t, sector;
+
+ if (!bsd_globals_ptr)
+ bsd_globals_ptr = xzalloc(sizeof(*bsd_globals_ptr));
+
+ d = &xbsd_dlabel;
+
+ /* p is used only to get the starting sector */
+#if !defined(__alpha__)
+ sector = (p ? get_start_sect(p) : 0);
+#else
+ sector = 0;
+#endif
+
+ if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
+ fdisk_fatal(unable_to_seek);
+ if (BSD_BBSIZE != read(fd, disklabelbuffer, BSD_BBSIZE))
+ fdisk_fatal(unable_to_read);
+
+ memmove(d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
+ sizeof(struct xbsd_disklabel));
+
+ if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC)
+ return 0;
+
+ 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_npartitions > BSD_MAXPARTITIONS)
+ printf("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 = &xbsd_dlabel;
+ unsigned int sector;
+
+#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__hppa__)
+ sector = get_start_sect(p) + BSD_LABELSECTOR;
+#else
+ 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.
+ */
+ memmove(&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
+ d, sizeof(struct xbsd_disklabel));
+
+#if defined(__alpha__) && BSD_LABELSECTOR == 0
+ alpha_bootblock_checksum(disklabelbuffer);
+ if (lseek(fd, 0, SEEK_SET) == -1)
+ fdisk_fatal(unable_to_seek);
+ if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
+ fdisk_fatal(unable_to_write);
+#else
+ if (lseek(fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1)
+ fdisk_fatal(unable_to_seek);
+ if (sizeof(struct xbsd_disklabel) != write(fd, d, sizeof(struct xbsd_disklabel)))
+ fdisk_fatal(unable_to_write);
+#endif
+ sync_disks();
+ return 1;
+}
+
+
+#if !defined(__alpha__)
+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;
+ struct partition *p;
+
+ k = get_partition(1, partitions);
+
+ if (!xbsd_check_new_partition(&i))
+ return;
+
+ p = get_part_table(k);
+
+ xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
+ xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
+ xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
+}
+#endif
+
+#if defined(__alpha__)
+static void
+alpha_bootblock_checksum(char *boot)
+{
+ uint64_t *dp, sum;
+ int i;
+
+ dp = (uint64_t *)boot;
+ sum = 0;
+ for (i = 0; i < 63; i++)
+ sum += dp[i];
+ dp[63] = sum;
+}
+#endif /* __alpha__ */
+
+/* Undefine 'global' tricks */
+#undef disklabelbuffer
+#undef xbsd_dlabel
+
+#endif /* OSF_LABEL */
diff --git a/i/pc104/initrd/conf/busybox/util-linux/fdisk_sgi.c b/i/pc104/initrd/conf/busybox/util-linux/fdisk_sgi.c
new file mode 100644
index 0000000..b2e0d7a
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/fdisk_sgi.c
@@ -0,0 +1,891 @@
+#if ENABLE_FEATURE_SGI_LABEL
+
+/*
+ * Copyright (C) Andreas Neuper, Sep 1998.
+ * This file may be modified and redistributed under
+ * the terms of the GNU Public License.
+ */
+
+#define SGI_VOLHDR 0x00
+/* 1 and 2 were used for drive types no longer supported by SGI */
+#define SGI_SWAP 0x03
+/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
+#define SGI_VOLUME 0x06
+#define SGI_EFS 0x07
+#define SGI_LVOL 0x08
+#define SGI_RLVOL 0x09
+#define SGI_XFS 0x0a
+#define SGI_XFSLOG 0x0b
+#define SGI_XLV 0x0c
+#define SGI_XVM 0x0d
+#define SGI_ENTIRE_DISK SGI_VOLUME
+
+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;
+};
+
+/*
+ * 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]; /* a character array */
+ unsigned int vol_file_start; /* number of logical block */
+ unsigned int vol_file_size; /* number of bytes */
+ } directory[15];
+ struct sgi_partinfo { /* 16 * 12 bytes */
+ unsigned int num_sectors; /* number of blocks */
+ unsigned int start_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 SGI_SSWAP16(x) (sgi_other_endian ? fdisk_swap16(x) : (uint16_t)(x))
+#define SGI_SSWAP32(x) (sgi_other_endian ? fdisk_swap32(x) : (uint32_t)(x))
+
+#define sgilabel ((sgi_partition *)MBRbuffer)
+#define sgiparam (sgilabel->devparam)
+
+/*
+ *
+ * fdisksgilabel.c
+ *
+ * Copyright (C) Andreas Neuper, Sep 1998.
+ * This file may be modified and redistributed under
+ * the terms of the GNU Public License.
+ *
+ * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ * Internationalization
+ */
+
+
+static int sgi_other_endian;
+static int debug;
+static short sgi_volumes = 1;
+
+/*
+ * only dealing with free blocks here
+ */
+
+typedef struct {
+ unsigned int first;
+ unsigned int last;
+} freeblocks;
+static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
+
+static void
+setfreelist(int i, unsigned int f, unsigned int l)
+{
+ freelist[i].first = f;
+ freelist[i].last = l;
+}
+
+static void
+add2freelist(unsigned int f, unsigned int l)
+{
+ int i;
+ for (i = 0; i < 17 ; i++)
+ if (freelist[i].last == 0)
+ break;
+ setfreelist(i, f, l);
+}
+
+static void
+clearfreelist(void)
+{
+ int i;
+
+ for (i = 0; i < 17 ; i++)
+ setfreelist(i, 0, 0);
+}
+
+static unsigned int
+isinfreelist(unsigned int b)
+{
+ int i;
+
+ for (i = 0; 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
+ */
+
+static const char *const sgi_sys_types[] = {
+/* SGI_VOLHDR */ "\x00" "SGI volhdr" ,
+/* 0x01 */ "\x01" "SGI trkrepl" ,
+/* 0x02 */ "\x02" "SGI secrepl" ,
+/* SGI_SWAP */ "\x03" "SGI raw" ,
+/* 0x04 */ "\x04" "SGI bsd" ,
+/* 0x05 */ "\x05" "SGI sysv" ,
+/* SGI_ENTIRE_DISK */ "\x06" "SGI volume" ,
+/* SGI_EFS */ "\x07" "SGI efs" ,
+/* 0x08 */ "\x08" "SGI lvol" ,
+/* 0x09 */ "\x09" "SGI rlvol" ,
+/* SGI_XFS */ "\x0a" "SGI xfs" ,
+/* SGI_XFSLOG */ "\x0b" "SGI xfslog" ,
+/* SGI_XLV */ "\x0c" "SGI xlv" ,
+/* SGI_XVM */ "\x0d" "SGI xvm" ,
+/* LINUX_SWAP */ "\x82" "Linux swap" ,
+/* LINUX_NATIVE */ "\x83" "Linux native",
+/* LINUX_LVM */ "\x8d" "Linux LVM" ,
+/* LINUX_RAID */ "\xfd" "Linux RAID" ,
+ NULL
+};
+
+
+static int
+sgi_get_nsect(void)
+{
+ return SGI_SSWAP16(sgilabel->devparam.nsect);
+}
+
+static int
+sgi_get_ntrks(void)
+{
+ return SGI_SSWAP16(sgilabel->devparam.ntrks);
+}
+
+static unsigned int
+two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
+{
+ int i = 0;
+ unsigned int sum = 0;
+
+ size /= sizeof(unsigned int);
+ for (i = 0; i < size; i++)
+ sum -= SGI_SSWAP32(base[i]);
+ return sum;
+}
+
+void BUG_bad_sgi_partition_size(void);
+
+static int
+check_sgi_label(void)
+{
+ if (sizeof(sgi_partition) > 512) {
+ /* According to MIPS Computer Systems, Inc the label
+ * must not contain more than 512 bytes */
+ BUG_bad_sgi_partition_size();
+ }
+
+ if (sgilabel->magic != SGI_LABEL_MAGIC
+ && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED
+ ) {
+ current_label_type = label_dos;
+ return 0;
+ }
+
+ sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
+ /*
+ * test for correct checksum
+ */
+ if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
+ sizeof(*sgilabel))) {
+ printf("Detected sgi disklabel with wrong checksum\n");
+ }
+ update_units();
+ current_label_type = label_sgi;
+ partitions = 16;
+ sgi_volumes = 15;
+ return 1;
+}
+
+static unsigned int
+sgi_get_start_sector(int i)
+{
+ return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
+}
+
+static unsigned int
+sgi_get_num_sectors(int i)
+{
+ return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
+}
+
+static int
+sgi_get_sysid(int i)
+{
+ return SGI_SSWAP32(sgilabel->partitions[i].id);
+}
+
+static int
+sgi_get_bootpartition(void)
+{
+ return SGI_SSWAP16(sgilabel->boot_part);
+}
+
+static int
+sgi_get_swappartition(void)
+{
+ return SGI_SSWAP16(sgilabel->swap_part);
+}
+
+static void
+sgi_list_table(int xtra)
+{
+ int i, w, wd;
+ int kpi = 0; /* kernel partition ID */
+
+ 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 = %s of %d * 512 bytes\n\n",
+ disk_device, heads, sectors, cylinders,
+ SGI_SSWAP16(sgiparam.pcylcount),
+ SGI_SSWAP16(sgiparam.sparecyl),
+ SGI_SSWAP16(sgiparam.ilfact),
+ (char *)sgilabel,
+ str_units(PLURAL), units_per_sector);
+ } else {
+ printf("\nDisk %s (SGI disk label): "
+ "%d heads, %d sectors, %d cylinders\n"
+ "Units = %s of %d * 512 bytes\n\n",
+ disk_device, heads, sectors, cylinders,
+ str_units(PLURAL), units_per_sector );
+ }
+
+ w = strlen(disk_device);
+ wd = sizeof("Device") - 1;
+ if (w < wd)
+ w = wd;
+
+ printf("----- partitions -----\n"
+ "Pt# %*s Info Start End Sectors Id System\n",
+ w + 2, "Device");
+ for (i = 0 ; i < partitions; i++) {
+ if (sgi_get_num_sectors(i) || debug ) {
+ uint32_t start = sgi_get_start_sector(i);
+ uint32_t len = sgi_get_num_sectors(i);
+ kpi++; /* only count nonempty partitions */
+ printf(
+ "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
+/* fdisk part number */ i+1,
+/* device */ partname(disk_device, kpi, w+3),
+/* 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 */ partition_type(sgi_get_sysid(i)));
+ }
+ }
+ printf("----- Bootinfo -----\nBootfile: %s\n"
+ "----- Directory Entries -----\n",
+ sgilabel->boot_file);
+ for (i = 0 ; i < sgi_volumes; i++) {
+ if (sgilabel->directory[i].vol_file_size) {
+ uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
+ uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
+ unsigned char *name = sgilabel->directory[i].vol_file_name;
+
+ printf("%2d: %-10s sector%5u size%8u\n",
+ i, (char*)name, (unsigned int) start, (unsigned int) len);
+ }
+ }
+}
+
+static void
+sgi_set_bootpartition(int i)
+{
+ sgilabel->boot_part = SGI_SSWAP16(((short)i));
+}
+
+static unsigned int
+sgi_get_lastblock(void)
+{
+ return heads * sectors * cylinders;
+}
+
+static void
+sgi_set_swappartition(int i)
+{
+ sgilabel->swap_part = SGI_SSWAP16(((short)i));
+}
+
+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;
+ }
+ if (strlen(aFile) > 16) {
+ printf("\nName of Bootfile too long (>16 bytes)\n");
+ return 0;
+ }
+ if (aFile[0] != '/') {
+ printf("\nBootfile must have a fully qualified pathname\n");
+ return 0;
+ }
+ if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
+ printf("\nBe aware, that the bootfile is not checked for existence.\n"
+ "\tSGI's default is \"/unix\" and for backup \"/unix.save\".\n");
+ /* filename is correct and did change */
+ return 1;
+ }
+ return 0; /* filename did not change */
+}
+
+static const char *
+sgi_get_bootfile(void)
+{
+ return (char*)sgilabel->boot_file;
+}
+
+static 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);
+ }
+}
+
+static void
+create_sgiinfo(void)
+{
+ /* I keep SGI's habit to write the sgilabel to the second block */
+ sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
+ sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
+ strncpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8);
+}
+
+static sgiinfo *fill_sgiinfo(void);
+
+static void
+sgi_write_table(void)
+{
+ sgilabel->csum = 0;
+ sgilabel->csum = SGI_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)
+ fdisk_fatal(unable_to_seek);
+ if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
+ fdisk_fatal(unable_to_write);
+ if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
+ /*
+ * keep this habit of first writing the "sgilabel".
+ * I never tested whether it works without (AN 981002).
+ */
+ sgiinfo *info = fill_sgiinfo();
+ int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
+ if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
+ fdisk_fatal(unable_to_seek);
+ if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
+ fdisk_fatal(unable_to_write);
+ free(info);
+ }
+}
+
+static int
+compare_start(int *x, int *y)
+{
+ /*
+ * sort according to start sectors
+ * and prefers largest partition:
+ * entry zero is entire disk entry
+ */
+ unsigned int i = *x;
+ unsigned int j = *y;
+ unsigned int a = sgi_get_start_sector(i);
+ unsigned int b = sgi_get_start_sector(j);
+ unsigned int c = sgi_get_num_sectors(i);
+ unsigned int d = sgi_get_num_sectors(j);
+
+ if (a == b)
+ return (d > c) ? 1 : (d == c) ? 0 : -1;
+ return (a > b) ? 1 : -1;
+}
+
+
+static 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 entire = 0, i = 0;
+ unsigned int start = 0;
+ long long gap = 0; /* count unused blocks */
+ unsigned 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) == SGI_ENTIRE_DISK) {
+ if (entire++ == 1) {
+ if (verbose)
+ printf("More than one entire disk entry present\n");
+ }
+ }
+ }
+ }
+ if (sortcount == 0) {
+ if (verbose)
+ printf("No partitions defined\n");
+ return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
+ }
+ qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
+ if (sgi_get_sysid(Index[0]) == SGI_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,\n"
+ "not 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]) == SGI_ENTIRE_DISK) continue;
+ if (start > sgi_get_start_sector(Index[i])) {
+ if (verbose)
+ printf("Partitions %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 %8u sectors - sectors %8u-%8u\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 %8u sectors - sectors %8u-%8u\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 > 0) ? 1 : (gap == 0) ? 0 : -1;
+}
+
+static int
+sgi_gaps(void)
+{
+ /*
+ * 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);
+}
+
+static 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 != SGI_ENTIRE_DISK) && (sys != SGI_VOLHDR)
+ && (sgi_get_start_sector(i) < 1)
+ ) {
+ read_maybe_empty(
+ "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") != 0)
+ return;
+ }
+ sgilabel->partitions[i].id = SGI_SSWAP32(sys);
+}
+
+/* returns partition index of first entry marked as entire disk */
+static int
+sgi_entire(void)
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ if (sgi_get_sysid(i) == SGI_VOLUME)
+ return i;
+ return -1;
+}
+
+static void
+sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
+{
+ sgilabel->partitions[i].id = SGI_SSWAP32(sys);
+ sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
+ sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
+ set_changed(i);
+ if (sgi_gaps() < 0) /* rebuild freelist */
+ printf("Partition overlap detected\n");
+}
+
+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;
+ }
+ }
+}
+
+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;
+ }
+ }
+}
+
+static void
+sgi_delete_partition(int i)
+{
+ sgi_set_partition(i, 0, 0, 0);
+}
+
+static void
+sgi_add_partition(int n, int sys)
+{
+ char mesg[256];
+ unsigned int first = 0, last = 0;
+
+ if (n == 10) {
+ sys = SGI_VOLUME;
+ } else if (n == 8) {
+ sys = 0;
+ }
+ if (sgi_get_num_sectors(n)) {
+ printf(msg_part_already_defined, 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;
+ }
+ snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
+ while (1) {
+ 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 (display_in_cyl_units)
+ first *= units_per_sector;
+ else
+ first = first; /* align to cylinder if you know how ... */
+ if (!last )
+ last = isinfreelist(first);
+ if (last != 0)
+ break;
+ printf("You will get a partition overlap on the disk. "
+ "Fix it first!\n");
+ }
+ snprintf(mesg, sizeof(mesg), " Last %s", str_units(SINGULAR));
+ last = read_int(scround(first), scround(last)-1, scround(last)-1,
+ scround(first), mesg)+1;
+ if (display_in_cyl_units)
+ last *= units_per_sector;
+ 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);
+}
+
+#if ENABLE_FEATURE_FDISK_ADVANCED
+static void
+create_sgilabel(void)
+{
+ struct hd_geometry geometry;
+ struct {
+ unsigned int start;
+ unsigned int nsect;
+ int sysid;
+ } old[4];
+ int i = 0;
+ long longsectors; /* the number of sectors on the device */
+ int res; /* the result from the ioctl */
+ int sec_fac; /* the sector factor */
+
+ sec_fac = sector_size / 512; /* determine the sector factor */
+
+ printf(msg_building_new_label, "SGI disklabel");
+
+ sgi_other_endian = (BYTE_ORDER == LITTLE_ENDIAN);
+ res = ioctl(fd, BLKGETSIZE, &longsectors);
+ if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
+ heads = geometry.heads;
+ sectors = geometry.sectors;
+ if (res == 0) {
+ /* the get device size ioctl was successful */
+ cylinders = longsectors / (heads * sectors);
+ cylinders /= sec_fac;
+ } else {
+ /* otherwise print error and use truncated version */
+ cylinders = geometry.cylinders;
+ printf(
+"Warning: BLKGETSIZE ioctl failed on %s. Using geometry cylinder value of %d.\n"
+"This value may be truncated for devices > 33.8 GB.\n", disk_device, cylinders);
+ }
+ }
+ for (i = 0; i < 4; i++) {
+ old[i].sysid = 0;
+ if (valid_part_table_flag(MBRbuffer)) {
+ if (get_part_table(i)->sys_ind) {
+ old[i].sysid = get_part_table(i)->sys_ind;
+ old[i].start = get_start_sect(get_part_table(i));
+ old[i].nsect = get_nr_sects(get_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(MBRbuffer, 0, sizeof(MBRbuffer));
+ /* fields with '//' are already zeroed out by memset above */
+
+ sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
+ //sgilabel->boot_part = SGI_SSWAP16(0);
+ sgilabel->swap_part = SGI_SSWAP16(1);
+
+ //memset(sgilabel->boot_file, 0, 16);
+ strcpy((char*)sgilabel->boot_file, "/unix"); /* sizeof(sgilabel->boot_file) == 16 > 6 */
+
+ //sgilabel->devparam.skew = (0);
+ //sgilabel->devparam.gap1 = (0);
+ //sgilabel->devparam.gap2 = (0);
+ //sgilabel->devparam.sparecyl = (0);
+ sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
+ //sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
+ /* tracks/cylinder (heads) */
+ sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
+ //sgilabel->devparam.cmd_tag_queue_depth = (0);
+ //sgilabel->devparam.unused0 = (0);
+ //sgilabel->devparam.unused1 = SGI_SSWAP16(0);
+ /* sectors/track */
+ sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
+ sgilabel->devparam.bytes = SGI_SSWAP16(512);
+ sgilabel->devparam.ilfact = SGI_SSWAP16(1);
+ sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
+ IGNORE_ERRORS|RESEEK);
+ //sgilabel->devparam.datarate = SGI_SSWAP32(0);
+ sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
+ //sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
+ //sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
+ //sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
+ //sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
+ //sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
+ //sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
+ //sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
+ //memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
+ //memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partinfo)*16 );
+ current_label_type = label_sgi;
+ partitions = 16;
+ sgi_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);
+ }
+ }
+}
+
+static void
+sgi_set_xcyl(void)
+{
+ /* do nothing in the beginning */
+}
+#endif /* FEATURE_FDISK_ADVANCED */
+
+/* _____________________________________________________________
+ */
+
+static sgiinfo *
+fill_sgiinfo(void)
+{
+ sgiinfo *info = xzalloc(sizeof(sgiinfo));
+
+ info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
+ info->b1 = SGI_SSWAP32(-1);
+ info->b2 = SGI_SSWAP16(-1);
+ info->b3 = SGI_SSWAP16(1);
+ /* You may want to replace this string !!!!!!! */
+ strcpy( (char*)info->scsi_string, "IBM OEM 0662S12 3 30" );
+ strcpy( (char*)info->serial, "0000" );
+ info->check1816 = SGI_SSWAP16(18*256 +16 );
+ strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
+ return info;
+}
+#endif /* SGI_LABEL */
diff --git a/i/pc104/initrd/conf/busybox/util-linux/fdisk_sun.c b/i/pc104/initrd/conf/busybox/util-linux/fdisk_sun.c
new file mode 100644
index 0000000..2fa7b2b
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/fdisk_sun.c
@@ -0,0 +1,730 @@
+#if ENABLE_FEATURE_SUN_LABEL
+
+#define SUNOS_SWAP 3
+#define SUN_WHOLE_DISK 5
+
+#define SUN_LABEL_MAGIC 0xDABE
+#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
+#define SUN_SSWAP16(x) (sun_other_endian ? fdisk_swap16(x) : (uint16_t)(x))
+#define SUN_SSWAP32(x) (sun_other_endian ? fdisk_swap32(x) : (uint32_t)(x))
+
+/* Copied from linux/major.h */
+#define FLOPPY_MAJOR 2
+
+#define SCSI_IOCTL_GET_IDLUN 0x5382
+
+/*
+ * 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.
+ *
+ * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ * Internationalization
+ */
+
+
+static int sun_other_endian;
+static int scsi_disk;
+static int floppy;
+
+#ifndef IDE0_MAJOR
+#define IDE0_MAJOR 3
+#endif
+#ifndef IDE1_MAJOR
+#define IDE1_MAJOR 22
+#endif
+
+static void
+guess_device_type(void)
+{
+ struct stat bootstat;
+
+ if (fstat(fd, &bootstat) < 0) {
+ scsi_disk = 0;
+ floppy = 0;
+ } else if (S_ISBLK(bootstat.st_mode)
+ && (major(bootstat.st_rdev) == IDE0_MAJOR ||
+ major(bootstat.st_rdev) == IDE1_MAJOR)) {
+ scsi_disk = 0;
+ floppy = 0;
+ } else if (S_ISBLK(bootstat.st_mode)
+ && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
+ scsi_disk = 0;
+ floppy = 1;
+ } else {
+ scsi_disk = 1;
+ floppy = 0;
+ }
+}
+
+static const char *const sun_sys_types[] = {
+ "\x00" "Empty" , /* 0 */
+ "\x01" "Boot" , /* 1 */
+ "\x02" "SunOS root" , /* 2 */
+ "\x03" "SunOS swap" , /* SUNOS_SWAP */
+ "\x04" "SunOS usr" , /* 4 */
+ "\x05" "Whole disk" , /* SUN_WHOLE_DISK */
+ "\x06" "SunOS stand" , /* 6 */
+ "\x07" "SunOS var" , /* 7 */
+ "\x08" "SunOS home" , /* 8 */
+ "\x82" "Linux swap" , /* LINUX_SWAP */
+ "\x83" "Linux native", /* LINUX_NATIVE */
+ "\x8e" "Linux LVM" , /* 0x8e */
+/* New (2.2.x) raid partition with autodetect using persistent superblock */
+ "\xfd" "Linux raid autodetect", /* 0xfd */
+ NULL
+};
+
+
+static void
+set_sun_partition(int i, uint start, uint stop, int sysid)
+{
+ sunlabel->infos[i].id = sysid;
+ sunlabel->partitions[i].start_cylinder =
+ SUN_SSWAP32(start / (heads * sectors));
+ sunlabel->partitions[i].num_sectors =
+ SUN_SSWAP32(stop - start);
+ set_changed(i);
+}
+
+static int
+check_sun_label(void)
+{
+ unsigned short *ush;
+ int csum;
+
+ if (sunlabel->magic != SUN_LABEL_MAGIC
+ && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
+ current_label_type = label_dos;
+ sun_other_endian = 0;
+ return 0;
+ }
+ sun_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) {
+ printf("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 = SUN_SSWAP16(sunlabel->ntrks);
+ cylinders = SUN_SSWAP16(sunlabel->ncyl);
+ sectors = SUN_SSWAP16(sunlabel->nsect);
+ }
+ update_units();
+ current_label_type = label_sun;
+ partitions = 8;
+ return 1;
+}
+
+static const struct sun_predefined_drives {
+ const char *vendor;
+ const 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},
+ { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
+ { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
+ { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
+ { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
+ { "","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},
+};
+
+static const struct sun_predefined_drives *
+sun_autoconfigure_scsi(void)
+{
+ const 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))
+ return NULL;
+
+ sprintf(buffer,
+ "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
+ /* 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,
+ (id[0]>>16) & 0xff,
+ id[0] & 0xff,
+ (id[0]>>8) & 0xff
+ );
+ pfd = fopen("/proc/scsi/scsi", "r");
+ if (!pfd) {
+ return NULL;
+ }
+ while (fgets(buffer2, 2048, pfd)) {
+ if (strcmp(buffer, buffer2))
+ continue;
+ if (!fgets(buffer2, 2048, pfd))
+ break;
+ q = strstr(buffer2, "Vendor: ");
+ if (!q)
+ break;
+ q += 8;
+ vendor = q;
+ q = strstr(q, " ");
+ *q++ = '\0'; /* truncate vendor name */
+ q = strstr(q, "Model: ");
+ if (!q)
+ break;
+ *q = '\0';
+ q += 7;
+ model = q;
+ q = strstr(q, " Rev: ");
+ if (!q)
+ break;
+ *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;
+}
+
+static void
+create_sunlabel(void)
+{
+ struct hd_geometry geometry;
+ unsigned int ndiv;
+ int i;
+ unsigned char c;
+ const struct sun_predefined_drives *p = NULL;
+
+ printf(msg_building_new_label, "sun disklabel");
+
+ sun_other_endian = BB_LITTLE_ENDIAN;
+ memset(MBRbuffer, 0, sizeof(MBRbuffer));
+ sunlabel->magic = SUN_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);
+ }
+ while (1) {
+ c = read_nonempty("Select type (? for auto, 0 for custom): ");
+ if (c == '0') {
+ break;
+ }
+ if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
+ p = sun_drives + c - 'a';
+ break;
+ }
+ if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
+ p = sun_drives + c - 'A';
+ break;
+ }
+ if (c == '?' && scsi_disk) {
+ p = sun_autoconfigure_scsi();
+ if (p)
+ break;
+ printf("Autoconfigure failed\n");
+ }
+ }
+ }
+ if (!p || floppy) {
+ if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
+ heads = geometry.heads;
+ sectors = geometry.sectors;
+ cylinders = geometry.cylinders;
+ } else {
+ heads = 0;
+ sectors = 0;
+ cylinders = 0;
+ }
+ if (floppy) {
+ sunlabel->nacyl = 0;
+ sunlabel->pcylcount = SUN_SSWAP16(cylinders);
+ sunlabel->rspeed = SUN_SSWAP16(300);
+ sunlabel->ilfact = SUN_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 = SUN_SSWAP16(read_int(0, 2, 65535, 0, "Alternate cylinders"));
+ sunlabel->pcylcount = SUN_SSWAP16(read_int(0, cylinders+SUN_SSWAP16(sunlabel->nacyl), 65535, 0, "Physical cylinders"));
+ sunlabel->rspeed = SUN_SSWAP16(read_int(1, 5400, 100000, 0, "Rotation speed (rpm)"));
+ sunlabel->ilfact = SUN_SSWAP16(read_int(1, 1, 32, 0, "Interleave factor"));
+ sunlabel->sparecyl = SUN_SSWAP16(read_int(0, 0, sectors, 0, "Extra sectors per cylinder"));
+ }
+ } else {
+ sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
+ sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
+ sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
+ sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
+ sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
+ sunlabel->nsect = SUN_SSWAP16(p->nsect);
+ sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
+ sunlabel->ilfact = SUN_SSWAP16(1);
+ cylinders = p->ncyl;
+ heads = p->ntrks;
+ sectors = p->nsect;
+ puts("You may change all the disk params from the x menu");
+ }
+
+ snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
+ "%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, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
+
+ sunlabel->ntrks = SUN_SSWAP16(heads);
+ sunlabel->nsect = SUN_SSWAP16(sectors);
+ sunlabel->ncyl = SUN_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, SUN_WHOLE_DISK);
+ {
+ unsigned short *ush = (unsigned short *)sunlabel;
+ unsigned short csum = 0;
+ while (ush < (unsigned short *)(&sunlabel->csum))
+ csum ^= *ush++;
+ sunlabel->csum = csum;
+ }
+
+ set_all_unchanged();
+ set_changed(0);
+ get_boot(create_empty_sun);
+}
+
+static 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;
+ set_changed(i);
+}
+
+static 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 != SUN_WHOLE_DISK) {
+ starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
+ lens[i] = SUN_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;
+
+static 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;
+}
+
+static 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);
+}
+
+static void
+add_sun_partition(int n, int sys)
+{
+ uint start, stop, stop2;
+ uint starts[8], lens[8];
+ int whole_disk = 0;
+
+ char mesg[256];
+ int i, first, last;
+
+ if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
+ printf(msg_part_already_defined, 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.\n"
+ "Delete/shrink them before retry.\n");
+ return;
+ }
+ }
+ snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
+ while (1) {
+ 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 (display_in_cyl_units)
+ first *= units_per_sector;
+ 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");
+ /* ewt asks to add: "don't start a partition at cyl 0"
+ However, edmundo@rano.demon.co.uk writes:
+ "In addition to having a Sun partition table, to be able to
+ boot from the disc, the first partition, /dev/sdX1, must
+ start at cylinder 0. This means that /dev/sdX1 contains
+ the partition table and the boot block, as these are the
+ first two sectors of the disc. Therefore you must be
+ careful what you use /dev/sdX1 for. In particular, you must
+ not use a partition starting at cylinder 0 for Linux swap,
+ as that would overwrite the partition table and the boot
+ block. You may, however, use such a partition for a UFS
+ or EXT2 file system, as these file systems leave the first
+ 1024 bytes undisturbed. */
+ /* On the other hand, one should not use partitions
+ starting at block 0 in an md, or the label will
+ be trashed. */
+ 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];
+ }
+ snprintf(mesg, sizeof(mesg),
+ "Last %s or +size or +sizeM or +sizeK",
+ str_units(SINGULAR));
+ 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 (display_in_cyl_units)
+ last *= units_per_sector;
+ if (n == 2 && !first) {
+ if (last >= stop2) {
+ whole_disk = 1;
+ last = stop2;
+ } else if (last > stop) {
+ printf(
+"You haven't covered the whole disk with the 3rd partition,\n"
+"but your value %d %s covers some other partition.\n"
+"Your entry has been changed to %d %s\n",
+ scround(last), str_units(SINGULAR),
+ scround(stop), str_units(SINGULAR));
+ last = stop;
+ }
+ } else if (!whole_disk && last > stop)
+ last = stop;
+
+ if (whole_disk)
+ sys = SUN_WHOLE_DISK;
+ set_sun_partition(n, first, last, sys);
+}
+
+static void
+sun_delete_partition(int i)
+{
+ unsigned int nsec;
+
+ if (i == 2
+ && sunlabel->infos[i].id == SUN_WHOLE_DISK
+ && !sunlabel->partitions[i].start_cylinder
+ && (nsec = SUN_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", nsec);
+ sunlabel->infos[i].id = 0;
+ sunlabel->partitions[i].num_sectors = 0;
+}
+
+static void
+sun_change_sysid(int i, int sys)
+{
+ if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
+ read_maybe_empty(
+ "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;
+}
+
+static void
+sun_list_table(int xtra)
+{
+ int i, w;
+
+ 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 = %s of %d * 512 bytes\n\n",
+ disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
+ cylinders, SUN_SSWAP16(sunlabel->nacyl),
+ SUN_SSWAP16(sunlabel->pcylcount),
+ SUN_SSWAP16(sunlabel->sparecyl),
+ SUN_SSWAP16(sunlabel->ilfact),
+ (char *)sunlabel,
+ str_units(PLURAL), units_per_sector);
+ else
+ printf(
+ "\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
+ "Units = %s of %d * 512 bytes\n\n",
+ disk_device, heads, sectors, cylinders,
+ str_units(PLURAL), units_per_sector);
+
+ printf("%*s Flag Start End Blocks Id System\n",
+ w + 1, "Device");
+ for (i = 0 ; i < partitions; i++) {
+ if (sunlabel->partitions[i].num_sectors) {
+ uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
+ uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
+ printf("%s %c%c %9ld %9ld %9ld%c %2x %s\n",
+ partname(disk_device, i+1, w), /* device */
+ (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
+ (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
+ (long) scround(start), /* start */
+ (long) scround(start+len), /* end */
+ (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
+ sunlabel->infos[i].id, /* type id */
+ partition_type(sunlabel->infos[i].id)); /* type name */
+ }
+ }
+}
+
+#if ENABLE_FEATURE_FDISK_ADVANCED
+
+static void
+sun_set_alt_cyl(void)
+{
+ sunlabel->nacyl =
+ SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
+ "Number of alternate cylinders"));
+}
+
+static void
+sun_set_ncyl(int cyl)
+{
+ sunlabel->ncyl = SUN_SSWAP16(cyl);
+}
+
+static void
+sun_set_xcyl(void)
+{
+ sunlabel->sparecyl =
+ SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
+ "Extra sectors per cylinder"));
+}
+
+static void
+sun_set_ilfact(void)
+{
+ sunlabel->ilfact =
+ SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
+ "Interleave factor"));
+}
+
+static void
+sun_set_rspeed(void)
+{
+ sunlabel->rspeed =
+ SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
+ "Rotation speed (rpm)"));
+}
+
+static void
+sun_set_pcylcount(void)
+{
+ sunlabel->pcylcount =
+ SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
+ "Number of physical cylinders"));
+}
+#endif /* FEATURE_FDISK_ADVANCED */
+
+static 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)
+ fdisk_fatal(unable_to_seek);
+ if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
+ fdisk_fatal(unable_to_write);
+}
+#endif /* SUN_LABEL */
diff --git a/i/pc104/initrd/conf/busybox/util-linux/freeramdisk.c b/i/pc104/initrd/conf/busybox/util-linux/freeramdisk.c
new file mode 100644
index 0000000..ae341b0
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/freeramdisk.c
@@ -0,0 +1,35 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * freeramdisk and fdflush implementations for busybox
+ *
+ * Copyright (C) 2000 and written by Emanuele Caratti <wiz@iol.it>
+ * Adjusted a bit by Erik Andersen <andersen@codepoet.org>
+ * Unified with fdflush by Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include "busybox.h"
+
+/* From <linux/fd.h> */
+#define FDFLUSH _IO(2,0x4b)
+
+int freeramdisk_main(int argc, char **argv);
+int freeramdisk_main(int argc, char **argv)
+{
+ int result;
+ int fd;
+
+ if (argc != 2) bb_show_usage();
+
+ fd = xopen(argv[1], O_RDWR);
+
+ // Act like freeramdisk, fdflush, or both depending on configuration.
+ result = ioctl(fd, (ENABLE_FREERAMDISK && applet_name[1]=='r')
+ || !ENABLE_FDFLUSH ? BLKFLSBUF : FDFLUSH);
+
+ if (ENABLE_FEATURE_CLEAN_UP) close(fd);
+
+ if (result) bb_perror_msg_and_die("%s", argv[1]);
+ return EXIT_SUCCESS;
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/fsck_minix.c b/i/pc104/initrd/conf/busybox/util-linux/fsck_minix.c
new file mode 100644
index 0000000..cc73cdd
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/fsck_minix.c
@@ -0,0 +1,1390 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * fsck.c - a file system consistency checker for Linux.
+ *
+ * (C) 1991, 1992 Linus Torvalds.
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+/*
+ * 09.11.91 - made the first rudimentary functions
+ *
+ * 10.11.91 - updated, does checking, no repairs yet.
+ * Sent out to the mailing-list for testing.
+ *
+ * 14.11.91 - Testing seems to have gone well. Added some
+ * correction-code, and changed some functions.
+ *
+ * 15.11.91 - More correction code. Hopefully it notices most
+ * cases now, and tries to do something about them.
+ *
+ * 16.11.91 - More corrections (thanks to Mika Jalava). Most
+ * things seem to work now. Yeah, sure.
+ *
+ *
+ * 19.04.92 - Had to start over again from this old version, as a
+ * kernel bug ate my enhanced fsck in february.
+ *
+ * 28.02.93 - added support for different directory entry sizes..
+ *
+ * Sat Mar 6 18:59:42 1993, faith@cs.unc.edu: Output namelen with
+ * super-block information
+ *
+ * Sat Oct 9 11:17:11 1993, faith@cs.unc.edu: make exit status conform
+ * to that required by fsutil
+ *
+ * Mon Jan 3 11:06:52 1994 - Dr. Wettstein (greg%wind.uucp@plains.nodak.edu)
+ * Added support for file system valid flag. Also
+ * added program_version variable and output of
+ * program name and version number when program
+ * is executed.
+ *
+ * 30.10.94 - added support for v2 filesystem
+ * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
+ *
+ * 10.12.94 - added test to prevent checking of mounted fs adapted
+ * from Theodore Ts'o's (tytso@athena.mit.edu) e2fsck
+ * program. (Daniel Quinlan, quinlan@yggdrasil.com)
+ *
+ * 01.07.96 - Fixed the v2 fs stuff to use the right #defines and such
+ * for modern libcs (janl@math.uio.no, Nicolai Langfeldt)
+ *
+ * 02.07.96 - Added C bit fiddling routines from rmk@ecs.soton.ac.uk
+ * (Russell King). He made them for ARM. It would seem
+ * that the ARM is powerful enough to do this in C whereas
+ * i386 and m64k must use assembly to get it fast >:-)
+ * This should make minix fsck system-independent.
+ * (janl@math.uio.no, Nicolai Langfeldt)
+ *
+ * 04.11.96 - Added minor fixes from Andreas Schwab to avoid compiler
+ * warnings. Added mc68k bitops from
+ * Joerg Dorchain <dorchain@mpi-sb.mpg.de>.
+ *
+ * 06.11.96 - Added v2 code submitted by Joerg Dorchain, but written by
+ * Andreas Schwab.
+ *
+ * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
+ * - added Native Language Support
+ *
+ *
+ * I've had no time to add comments - hopefully the function names
+ * are comments enough. As with all file system checkers, this assumes
+ * the file system is quiescent - don't use it on a mounted device
+ * unless you can be sure nobody is writing to it (and remember that the
+ * kernel can write to it when it searches for files).
+ *
+ * Usage: fsck [-larvsm] device
+ * -l for a listing of all the filenames
+ * -a for automatic repairs (not implemented)
+ * -r for repairs (interactive) (not implemented)
+ * -v for verbose (tells how many files)
+ * -s for super-block info
+ * -m for minix-like "mode not cleared" warnings
+ * -f force filesystem check even if filesystem marked as valid
+ *
+ * The device may be a block device or a image of one, but this isn't
+ * enforced (but it's not much fun on a character device :-).
+ */
+
+#include "busybox.h"
+#include <mntent.h>
+
+#include "minix.h"
+
+#ifndef BLKGETSIZE
+#define BLKGETSIZE _IO(0x12,96) /* return device size */
+#endif
+
+#ifdef UNUSED
+enum {
+ MINIX1_LINK_MAX = 250,
+ MINIX2_LINK_MAX = 65530,
+ MINIX_I_MAP_SLOTS = 8,
+ MINIX_Z_MAP_SLOTS = 64,
+ MINIX_V1 = 0x0001, /* original minix fs */
+ MINIX_V2 = 0x0002, /* minix V2 fs */
+ NAME_MAX = 255, /* # chars in a file name */
+};
+#endif
+
+#if ENABLE_FEATURE_MINIX2
+static smallint version2;
+#else
+enum { version2 = 0 };
+#endif
+
+#define PROGRAM_VERSION "1.2 - 11/11/96"
+static smallint repair, automatic, verbose, list, show, warn_mode, force;
+static smallint changed; /* is filesystem modified? */
+static smallint errors_uncorrected; /* flag if some error was not corrected */
+
+static smallint termios_set;
+static struct termios termios;
+
+static char *device_name;
+static int IN;
+static int directory, regular, blockdev, chardev, links, symlinks, total;
+
+//also smallint?
+static int dirsize = 16;
+static int namelen = 14;
+
+static char *inode_buffer;
+
+static struct {
+ char super_block_buffer[BLOCK_SIZE];
+ char add_zone_ind_blk[BLOCK_SIZE];
+ char add_zone_dind_blk[BLOCK_SIZE];
+ USE_FEATURE_MINIX2(char add_zone_tind_blk[BLOCK_SIZE];)
+ char check_file_blk[BLOCK_SIZE];
+} *blockbuf;
+
+#define Inode1 (((struct minix1_inode *) inode_buffer)-1)
+#define Inode2 (((struct minix2_inode *) inode_buffer)-1)
+
+#define Super (*(struct minix_super_block *)(blockbuf->super_block_buffer))
+
+#if ENABLE_FEATURE_MINIX2
+# define ZONES ((unsigned)(version2 ? Super.s_zones : Super.s_nzones))
+#else
+# define ZONES ((unsigned)(Super.s_nzones))
+#endif
+#define INODES ((unsigned)Super.s_ninodes)
+#define IMAPS ((unsigned)Super.s_imap_blocks)
+#define ZMAPS ((unsigned)Super.s_zmap_blocks)
+#define FIRSTZONE ((unsigned)Super.s_firstdatazone)
+#define ZONESIZE ((unsigned)Super.s_log_zone_size)
+#define MAXSIZE ((unsigned)Super.s_max_size)
+#define MAGIC (Super.s_magic)
+
+/* gcc likes this more (code is smaller) than macro variant */
+static ATTRIBUTE_ALWAYS_INLINE unsigned div_roundup(unsigned size, unsigned n)
+{
+ return (size + n-1) / n;
+}
+
+#if ENABLE_FEATURE_MINIX2
+#define INODE_BLOCKS div_roundup(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
+ : MINIX1_INODES_PER_BLOCK))
+#else
+#define INODE_BLOCKS div_roundup(INODES, MINIX1_INODES_PER_BLOCK)
+#endif
+
+#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
+#define NORM_FIRSTZONE (2 + IMAPS + ZMAPS + INODE_BLOCKS)
+
+static char *inode_map;
+static char *zone_map;
+
+static unsigned char *inode_count;
+static unsigned char *zone_count;
+
+/* Before you ask "where they come from?": */
+/* setbit/clrbit are supplied by sys/param.h */
+
+static int minix_bit(const char *a, unsigned i)
+{
+ return (a[i >> 3] & (1<<(i & 7)));
+}
+
+static void minix_setbit(char *a, unsigned i)
+{
+ setbit(a, i);
+ changed = 1;
+}
+static void minix_clrbit(char *a, unsigned i)
+{
+ clrbit(a, i);
+ changed = 1;
+}
+
+/* Note: do not assume 0/1, it is 0/nonzero */
+#define zone_in_use(x) (minix_bit(zone_map,(x)-FIRSTZONE+1))
+#define inode_in_use(x) (minix_bit(inode_map,(x)))
+
+#define mark_inode(x) (minix_setbit(inode_map,(x)))
+#define unmark_inode(x) (minix_clrbit(inode_map,(x)))
+
+#define mark_zone(x) (minix_setbit(zone_map,(x)-FIRSTZONE+1))
+#define unmark_zone(x) (minix_clrbit(zone_map,(x)-FIRSTZONE+1))
+
+
+static void recursive_check(unsigned ino);
+#if ENABLE_FEATURE_MINIX2
+static void recursive_check2(unsigned ino);
+#endif
+
+static void die(const char *str) ATTRIBUTE_NORETURN;
+static void die(const char *str)
+{
+ if (termios_set)
+ tcsetattr(0, TCSANOW, &termios);
+ bb_error_msg_and_die("%s", str);
+}
+
+/* File-name data */
+enum { MAX_DEPTH = 32 };
+static int name_depth;
+static char *current_name;
+static char *name_component[MAX_DEPTH+1];
+
+/* Wed Feb 9 15:17:06 MST 2000 */
+/* dynamically allocate name_list (instead of making it static) */
+static void alloc_current_name(void)
+{
+ current_name = xmalloc(MAX_DEPTH * (BUFSIZ + 1));
+ current_name[0] = '/';
+ current_name[1] = '\0';
+ name_component[0] = &current_name[0];
+}
+
+#if ENABLE_FEATURE_CLEAN_UP
+/* execute this atexit() to deallocate name_list[] */
+/* piptigger was here */
+static void free_current_name(void)
+{
+ free(current_name);
+}
+#endif
+
+static void push_filename(const char *name)
+{
+ // /dir/dir/dir/file
+ // ^ ^ ^
+ // [0] [1] [2] <-name_component[i]
+ if (name_depth < MAX_DEPTH) {
+ int len;
+ char *p = name_component[name_depth];
+ *p++ = '/';
+ len = sprintf(p, "%.*s", namelen, name);
+ name_component[name_depth + 1] = p + len;
+ }
+ name_depth++;
+}
+
+static void pop_filename(void)
+{
+ name_depth--;
+ if (name_depth < MAX_DEPTH) {
+ *name_component[name_depth] = '\0';
+ if (!name_depth) {
+ current_name[0] = '/';
+ current_name[1] = '\0';
+ }
+ }
+}
+
+static int ask(const char *string, int def)
+{
+ int c;
+
+ if (!repair) {
+ puts("");
+ errors_uncorrected = 1;
+ return 0;
+ }
+ if (automatic) {
+ puts("");
+ if (!def)
+ errors_uncorrected = 1;
+ return def;
+ }
+ printf(def ? "%s (y/n)? " : "%s (n/y)? ", string);
+ for (;;) {
+ fflush(stdout);
+ c = getchar();
+ if (c == EOF) {
+ if (!def)
+ errors_uncorrected = 1;
+ return def;
+ }
+ c = toupper(c);
+ if (c == 'Y') {
+ def = 1;
+ break;
+ } else if (c == 'N') {
+ def = 0;
+ break;
+ } else if (c == ' ' || c == '\n')
+ break;
+ }
+ if (def)
+ printf("y\n");
+ else {
+ printf("n\n");
+ errors_uncorrected = 1;
+ }
+ return def;
+}
+
+/*
+ * Make certain that we aren't checking a filesystem that is on a
+ * mounted partition. Code adapted from e2fsck, Copyright (C) 1993,
+ * 1994 Theodore Ts'o. Also licensed under GPL.
+ */
+static void check_mount(void)
+{
+ FILE *f;
+ struct mntent *mnt;
+ int cont;
+ int fd;
+
+ f = setmntent(MOUNTED, "r");
+ if (f == NULL)
+ return;
+ while ((mnt = getmntent(f)) != NULL)
+ if (strcmp(device_name, mnt->mnt_fsname) == 0)
+ break;
+ endmntent(f);
+ if (!mnt)
+ return;
+
+ /*
+ * If the root is mounted read-only, then /etc/mtab is
+ * probably not correct; so we won't issue a warning based on
+ * it.
+ */
+ fd = open(MOUNTED, O_RDWR);
+ if (fd < 0 && errno == EROFS)
+ return;
+ close(fd);
+
+ printf("%s is mounted. ", device_name);
+ cont = 0;
+ if (isatty(0) && isatty(1))
+ cont = ask("Do you really want to continue", 0);
+ if (!cont) {
+ printf("Check aborted\n");
+ exit(0);
+ }
+}
+
+/*
+ * check_zone_nr checks to see that *nr is a valid zone nr. If it
+ * isn't, it will possibly be repaired. Check_zone_nr sets *corrected
+ * if an error was corrected, and returns the zone (0 for no zone
+ * or a bad zone-number).
+ */
+static int check_zone_nr2(uint32_t *nr, smallint *corrected)
+{
+ const char *msg;
+ if (!*nr)
+ return 0;
+ if (*nr < FIRSTZONE)
+ msg = "< FIRSTZONE";
+ else if (*nr >= ZONES)
+ msg = ">= ZONES";
+ else
+ return *nr;
+ printf("Zone nr %s in file '%s'. ", msg, current_name);
+ if (ask("Remove block", 1)) {
+ *nr = 0;
+ *corrected = 1;
+ }
+ return 0;
+}
+
+static int check_zone_nr(uint16_t *nr, smallint *corrected)
+{
+ uint32_t nr32 = *nr;
+ int r = check_zone_nr2(&nr32, corrected);
+ *nr = (uint16_t)nr32;
+ return r;
+}
+
+/*
+ * read-block reads block nr into the buffer at addr.
+ */
+static void read_block(unsigned nr, char *addr)
+{
+ if (!nr) {
+ memset(addr, 0, BLOCK_SIZE);
+ return;
+ }
+ if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET)) {
+ printf("%s: cannot seek to block in file '%s'\n",
+ bb_msg_read_error, current_name);
+ errors_uncorrected = 1;
+ memset(addr, 0, BLOCK_SIZE);
+ } else if (BLOCK_SIZE != read(IN, addr, BLOCK_SIZE)) {
+ printf("%s: bad block in file '%s'\n",
+ bb_msg_read_error, current_name);
+ errors_uncorrected = 1;
+ memset(addr, 0, BLOCK_SIZE);
+ }
+}
+
+/*
+ * write_block writes block nr to disk.
+ */
+static void write_block(unsigned nr, char *addr)
+{
+ if (!nr)
+ return;
+ if (nr < FIRSTZONE || nr >= ZONES) {
+ printf("Internal error: trying to write bad block\n"
+ "Write request ignored\n");
+ errors_uncorrected = 1;
+ return;
+ }
+ if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET))
+ die("seek failed in write_block");
+ if (BLOCK_SIZE != write(IN, addr, BLOCK_SIZE)) {
+ printf("%s: bad block in file '%s'\n",
+ bb_msg_write_error, current_name);
+ errors_uncorrected = 1;
+ }
+}
+
+/*
+ * map_block calculates the absolute block nr of a block in a file.
+ * It sets 'changed' if the inode has needed changing, and re-writes
+ * any indirect blocks with errors.
+ */
+static int map_block(struct minix1_inode *inode, unsigned blknr)
+{
+ uint16_t ind[BLOCK_SIZE >> 1];
+ uint16_t dind[BLOCK_SIZE >> 1];
+ int block, result;
+ smallint blk_chg;
+
+ if (blknr < 7)
+ return check_zone_nr(inode->i_zone + blknr, &changed);
+ blknr -= 7;
+ if (blknr < 512) {
+ block = check_zone_nr(inode->i_zone + 7, &changed);
+ read_block(block, (char *) ind);
+ blk_chg = 0;
+ result = check_zone_nr(blknr + ind, &blk_chg);
+ if (blk_chg)
+ write_block(block, (char *) ind);
+ return result;
+ }
+ blknr -= 512;
+ block = check_zone_nr(inode->i_zone + 8, &changed);
+ read_block(block, (char *) dind);
+ blk_chg = 0;
+ result = check_zone_nr(dind + (blknr / 512), &blk_chg);
+ if (blk_chg)
+ write_block(block, (char *) dind);
+ block = result;
+ read_block(block, (char *) ind);
+ blk_chg = 0;
+ result = check_zone_nr(ind + (blknr % 512), &blk_chg);
+ if (blk_chg)
+ write_block(block, (char *) ind);
+ return result;
+}
+
+#if ENABLE_FEATURE_MINIX2
+static int map_block2(struct minix2_inode *inode, unsigned blknr)
+{
+ uint32_t ind[BLOCK_SIZE >> 2];
+ uint32_t dind[BLOCK_SIZE >> 2];
+ uint32_t tind[BLOCK_SIZE >> 2];
+ int block, result;
+ smallint blk_chg;
+
+ if (blknr < 7)
+ return check_zone_nr2(inode->i_zone + blknr, &changed);
+ blknr -= 7;
+ if (blknr < 256) {
+ block = check_zone_nr2(inode->i_zone + 7, &changed);
+ read_block(block, (char *) ind);
+ blk_chg = 0;
+ result = check_zone_nr2(blknr + ind, &blk_chg);
+ if (blk_chg)
+ write_block(block, (char *) ind);
+ return result;
+ }
+ blknr -= 256;
+ if (blknr >= 256 * 256) {
+ block = check_zone_nr2(inode->i_zone + 8, &changed);
+ read_block(block, (char *) dind);
+ blk_chg = 0;
+ result = check_zone_nr2(dind + blknr / 256, &blk_chg);
+ if (blk_chg)
+ write_block(block, (char *) dind);
+ block = result;
+ read_block(block, (char *) ind);
+ blk_chg = 0;
+ result = check_zone_nr2(ind + blknr % 256, &blk_chg);
+ if (blk_chg)
+ write_block(block, (char *) ind);
+ return result;
+ }
+ blknr -= 256 * 256;
+ block = check_zone_nr2(inode->i_zone + 9, &changed);
+ read_block(block, (char *) tind);
+ blk_chg = 0;
+ result = check_zone_nr2(tind + blknr / (256 * 256), &blk_chg);
+ if (blk_chg)
+ write_block(block, (char *) tind);
+ block = result;
+ read_block(block, (char *) dind);
+ blk_chg = 0;
+ result = check_zone_nr2(dind + (blknr / 256) % 256, &blk_chg);
+ if (blk_chg)
+ write_block(block, (char *) dind);
+ block = result;
+ read_block(block, (char *) ind);
+ blk_chg = 0;
+ result = check_zone_nr2(ind + blknr % 256, &blk_chg);
+ if (blk_chg)
+ write_block(block, (char *) ind);
+ return result;
+}
+#endif
+
+static void write_super_block(void)
+{
+ /*
+ * Set the state of the filesystem based on whether or not there
+ * are uncorrected errors. The filesystem valid flag is
+ * unconditionally set if we get this far.
+ */
+ Super.s_state |= MINIX_VALID_FS | MINIX_ERROR_FS;
+ if (!errors_uncorrected)
+ Super.s_state &= ~MINIX_ERROR_FS;
+
+ if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET))
+ die("seek failed in write_super_block");
+ if (BLOCK_SIZE != write(IN, blockbuf->super_block_buffer, BLOCK_SIZE))
+ die("cannot write super-block");
+}
+
+static void write_tables(void)
+{
+ write_super_block();
+
+ if (IMAPS * BLOCK_SIZE != write(IN, inode_map, IMAPS * BLOCK_SIZE))
+ die("cannot write inode map");
+ if (ZMAPS * BLOCK_SIZE != write(IN, zone_map, ZMAPS * BLOCK_SIZE))
+ die("cannot write zone map");
+ if (INODE_BUFFER_SIZE != write(IN, inode_buffer, INODE_BUFFER_SIZE))
+ die("cannot write inodes");
+}
+
+static void get_dirsize(void)
+{
+ int block;
+ char blk[BLOCK_SIZE];
+ int size;
+
+#if ENABLE_FEATURE_MINIX2
+ if (version2)
+ block = Inode2[MINIX_ROOT_INO].i_zone[0];
+ else
+#endif
+ block = Inode1[MINIX_ROOT_INO].i_zone[0];
+ read_block(block, blk);
+ for (size = 16; size < BLOCK_SIZE; size <<= 1) {
+ if (strcmp(blk + size + 2, "..") == 0) {
+ dirsize = size;
+ namelen = size - 2;
+ return;
+ }
+ }
+ /* use defaults */
+}
+
+static void read_superblock(void)
+{
+ if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET))
+ die("seek failed");
+ if (BLOCK_SIZE != read(IN, blockbuf->super_block_buffer, BLOCK_SIZE))
+ die("cannot read super block");
+ /* already initialized to:
+ namelen = 14;
+ dirsize = 16;
+ version2 = 0;
+ */
+ if (MAGIC == MINIX1_SUPER_MAGIC) {
+ } else if (MAGIC == MINIX1_SUPER_MAGIC2) {
+ namelen = 30;
+ dirsize = 32;
+#if ENABLE_FEATURE_MINIX2
+ } else if (MAGIC == MINIX2_SUPER_MAGIC) {
+ version2 = 1;
+ } else if (MAGIC == MINIX2_SUPER_MAGIC2) {
+ namelen = 30;
+ dirsize = 32;
+ version2 = 1;
+#endif
+ } else
+ die("bad magic number in super-block");
+ if (ZONESIZE != 0 || BLOCK_SIZE != 1024)
+ die("only 1k blocks/zones supported");
+ if (IMAPS * BLOCK_SIZE * 8 < INODES + 1)
+ die("bad s_imap_blocks field in super-block");
+ if (ZMAPS * BLOCK_SIZE * 8 < ZONES - FIRSTZONE + 1)
+ die("bad s_zmap_blocks field in super-block");
+}
+
+static void read_tables(void)
+{
+ inode_map = xzalloc(IMAPS * BLOCK_SIZE);
+ zone_map = xzalloc(ZMAPS * BLOCK_SIZE);
+ inode_buffer = xmalloc(INODE_BUFFER_SIZE);
+ inode_count = xmalloc(INODES + 1);
+ zone_count = xmalloc(ZONES);
+ if (IMAPS * BLOCK_SIZE != read(IN, inode_map, IMAPS * BLOCK_SIZE))
+ die("cannot read inode map");
+ if (ZMAPS * BLOCK_SIZE != read(IN, zone_map, ZMAPS * BLOCK_SIZE))
+ die("cannot read zone map");
+ if (INODE_BUFFER_SIZE != read(IN, inode_buffer, INODE_BUFFER_SIZE))
+ die("cannot read inodes");
+ if (NORM_FIRSTZONE != FIRSTZONE) {
+ printf("warning: firstzone!=norm_firstzone\n");
+ errors_uncorrected = 1;
+ }
+ get_dirsize();
+ if (show) {
+ printf("%u inodes\n"
+ "%u blocks\n"
+ "Firstdatazone=%u (%u)\n"
+ "Zonesize=%u\n"
+ "Maxsize=%u\n"
+ "Filesystem state=%u\n"
+ "namelen=%u\n\n",
+ INODES,
+ ZONES,
+ FIRSTZONE, NORM_FIRSTZONE,
+ BLOCK_SIZE << ZONESIZE,
+ MAXSIZE,
+ Super.s_state,
+ namelen);
+ }
+}
+
+static struct minix1_inode *get_inode(unsigned nr)
+{
+ struct minix1_inode *inode;
+
+ if (!nr || nr > INODES)
+ return NULL;
+ total++;
+ inode = Inode1 + nr;
+ if (!inode_count[nr]) {
+ if (!inode_in_use(nr)) {
+ printf("Inode %d is marked as 'unused', but it is used "
+ "for file '%s'\n", nr, current_name);
+ if (repair) {
+ if (ask("Mark as 'in use'", 1))
+ mark_inode(nr);
+ else
+ errors_uncorrected = 1;
+ }
+ }
+ if (S_ISDIR(inode->i_mode))
+ directory++;
+ else if (S_ISREG(inode->i_mode))
+ regular++;
+ else if (S_ISCHR(inode->i_mode))
+ chardev++;
+ else if (S_ISBLK(inode->i_mode))
+ blockdev++;
+ else if (S_ISLNK(inode->i_mode))
+ symlinks++;
+ else if (S_ISSOCK(inode->i_mode));
+ else if (S_ISFIFO(inode->i_mode));
+ else {
+ printf("%s has mode %05o\n", current_name, inode->i_mode);
+ }
+
+ } else
+ links++;
+ if (!++inode_count[nr]) {
+ printf("Warning: inode count too big\n");
+ inode_count[nr]--;
+ errors_uncorrected = 1;
+ }
+ return inode;
+}
+
+#if ENABLE_FEATURE_MINIX2
+static struct minix2_inode *get_inode2(unsigned nr)
+{
+ struct minix2_inode *inode;
+
+ if (!nr || nr > INODES)
+ return NULL;
+ total++;
+ inode = Inode2 + nr;
+ if (!inode_count[nr]) {
+ if (!inode_in_use(nr)) {
+ printf("Inode %d is marked as 'unused', but it is used "
+ "for file '%s'\n", nr, current_name);
+ if (repair) {
+ if (ask("Mark as 'in use'", 1))
+ mark_inode(nr);
+ else
+ errors_uncorrected = 1;
+ }
+ }
+ if (S_ISDIR(inode->i_mode))
+ directory++;
+ else if (S_ISREG(inode->i_mode))
+ regular++;
+ else if (S_ISCHR(inode->i_mode))
+ chardev++;
+ else if (S_ISBLK(inode->i_mode))
+ blockdev++;
+ else if (S_ISLNK(inode->i_mode))
+ symlinks++;
+ else if (S_ISSOCK(inode->i_mode));
+ else if (S_ISFIFO(inode->i_mode));
+ else {
+ printf("%s has mode %05o\n", current_name, inode->i_mode);
+ }
+ } else
+ links++;
+ if (!++inode_count[nr]) {
+ printf("Warning: inode count too big\n");
+ inode_count[nr]--;
+ errors_uncorrected = 1;
+ }
+ return inode;
+}
+#endif
+
+static void check_root(void)
+{
+ struct minix1_inode *inode = Inode1 + MINIX_ROOT_INO;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ die("root inode isn't a directory");
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void check_root2(void)
+{
+ struct minix2_inode *inode = Inode2 + MINIX_ROOT_INO;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ die("root inode isn't a directory");
+}
+#else
+void check_root2(void);
+#endif
+
+static int add_zone(uint16_t *znr, smallint *corrected)
+{
+ int result;
+ int block;
+
+ result = 0;
+ block = check_zone_nr(znr, corrected);
+ if (!block)
+ return 0;
+ if (zone_count[block]) {
+ printf("Already used block is reused in file '%s'. ",
+ current_name);
+ if (ask("Clear", 1)) {
+ *znr = 0;
+ block = 0;
+ *corrected = 1;
+ return 0;
+ }
+ }
+ if (!zone_in_use(block)) {
+ printf("Block %d in file '%s' is marked as 'unused'. ",
+ block, current_name);
+ if (ask("Correct", 1))
+ mark_zone(block);
+ }
+ if (!++zone_count[block])
+ zone_count[block]--;
+ return block;
+}
+
+#if ENABLE_FEATURE_MINIX2
+static int add_zone2(uint32_t *znr, smallint *corrected)
+{
+ int result;
+ int block;
+
+ result = 0;
+ block = check_zone_nr2(znr, corrected);
+ if (!block)
+ return 0;
+ if (zone_count[block]) {
+ printf("Already used block is reused in file '%s'. ",
+ current_name);
+ if (ask("Clear", 1)) {
+ *znr = 0;
+ block = 0;
+ *corrected = 1;
+ return 0;
+ }
+ }
+ if (!zone_in_use(block)) {
+ printf("Block %d in file '%s' is marked as 'unused'. ",
+ block, current_name);
+ if (ask("Correct", 1))
+ mark_zone(block);
+ }
+ if (!++zone_count[block])
+ zone_count[block]--;
+ return block;
+}
+#endif
+
+static void add_zone_ind(uint16_t *znr, smallint *corrected)
+{
+#define blk (blockbuf->add_zone_ind_blk)
+ int i;
+ int block;
+ smallint chg_blk = 0;
+
+ block = add_zone(znr, corrected);
+ if (!block)
+ return;
+ read_block(block, blk);
+ for (i = 0; i < (BLOCK_SIZE >> 1); i++)
+ add_zone(i + (uint16_t *) blk, &chg_blk);
+ if (chg_blk)
+ write_block(block, blk);
+#undef blk
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void add_zone_ind2(uint32_t *znr, smallint *corrected)
+{
+#define blk (blockbuf->add_zone_ind_blk)
+ int i;
+ int block;
+ smallint chg_blk = 0;
+
+ block = add_zone2(znr, corrected);
+ if (!block)
+ return;
+ read_block(block, blk);
+ for (i = 0; i < BLOCK_SIZE >> 2; i++)
+ add_zone2(i + (uint32_t *) blk, &chg_blk);
+ if (chg_blk)
+ write_block(block, blk);
+#undef blk
+}
+#endif
+
+static void add_zone_dind(uint16_t *znr, smallint *corrected)
+{
+#define blk (blockbuf->add_zone_dind_blk)
+ int i;
+ int block;
+ smallint chg_blk = 0;
+
+ block = add_zone(znr, corrected);
+ if (!block)
+ return;
+ read_block(block, blk);
+ for (i = 0; i < (BLOCK_SIZE >> 1); i++)
+ add_zone_ind(i + (uint16_t *) blk, &chg_blk);
+ if (chg_blk)
+ write_block(block, blk);
+#undef blk
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void add_zone_dind2(uint32_t *znr, smallint *corrected)
+{
+#define blk (blockbuf->add_zone_dind_blk)
+ int i;
+ int block;
+ smallint chg_blk = 0;
+
+ block = add_zone2(znr, corrected);
+ if (!block)
+ return;
+ read_block(block, blk);
+ for (i = 0; i < BLOCK_SIZE >> 2; i++)
+ add_zone_ind2(i + (uint32_t *) blk, &chg_blk);
+ if (chg_blk)
+ write_block(block, blk);
+#undef blk
+}
+
+static void add_zone_tind2(uint32_t *znr, smallint *corrected)
+{
+#define blk (blockbuf->add_zone_tind_blk)
+ int i;
+ int block;
+ smallint chg_blk = 0;
+
+ block = add_zone2(znr, corrected);
+ if (!block)
+ return;
+ read_block(block, blk);
+ for (i = 0; i < BLOCK_SIZE >> 2; i++)
+ add_zone_dind2(i + (uint32_t *) blk, &chg_blk);
+ if (chg_blk)
+ write_block(block, blk);
+#undef blk
+}
+#endif
+
+static void check_zones(unsigned i)
+{
+ struct minix1_inode *inode;
+
+ if (!i || i > INODES)
+ return;
+ if (inode_count[i] > 1) /* have we counted this file already? */
+ return;
+ inode = Inode1 + i;
+ if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
+ !S_ISLNK(inode->i_mode)) return;
+ for (i = 0; i < 7; i++)
+ add_zone(i + inode->i_zone, &changed);
+ add_zone_ind(7 + inode->i_zone, &changed);
+ add_zone_dind(8 + inode->i_zone, &changed);
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void check_zones2(unsigned i)
+{
+ struct minix2_inode *inode;
+
+ if (!i || i > INODES)
+ return;
+ if (inode_count[i] > 1) /* have we counted this file already? */
+ return;
+ inode = Inode2 + i;
+ if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode)
+ && !S_ISLNK(inode->i_mode))
+ return;
+ for (i = 0; i < 7; i++)
+ add_zone2(i + inode->i_zone, &changed);
+ add_zone_ind2(7 + inode->i_zone, &changed);
+ add_zone_dind2(8 + inode->i_zone, &changed);
+ add_zone_tind2(9 + inode->i_zone, &changed);
+}
+#endif
+
+static void check_file(struct minix1_inode *dir, unsigned offset)
+{
+#define blk (blockbuf->check_file_blk)
+ struct minix1_inode *inode;
+ int ino;
+ char *name;
+ int block;
+
+ block = map_block(dir, offset / BLOCK_SIZE);
+ read_block(block, blk);
+ name = blk + (offset % BLOCK_SIZE) + 2;
+ ino = *(uint16_t *) (name - 2);
+ if (ino > INODES) {
+ printf("%s contains a bad inode number for file '%.*s'. ",
+ current_name, namelen, name);
+ if (ask("Remove", 1)) {
+ *(uint16_t *) (name - 2) = 0;
+ write_block(block, blk);
+ }
+ ino = 0;
+ }
+ push_filename(name);
+ inode = get_inode(ino);
+ pop_filename();
+ if (!offset) {
+ if (inode && LONE_CHAR(name, '.'))
+ return;
+ printf("%s: bad directory: '.' isn't first\n", current_name);
+ errors_uncorrected = 1;
+ }
+ if (offset == dirsize) {
+ if (inode && strcmp("..", name) == 0)
+ return;
+ printf("%s: bad directory: '..' isn't second\n", current_name);
+ errors_uncorrected = 1;
+ }
+ if (!inode)
+ return;
+ push_filename(name);
+ if (list) {
+ if (verbose)
+ printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
+ printf("%s%s\n", current_name, S_ISDIR(inode->i_mode) ? ":" : "");
+ }
+ check_zones(ino);
+ if (inode && S_ISDIR(inode->i_mode))
+ recursive_check(ino);
+ pop_filename();
+#undef blk
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void check_file2(struct minix2_inode *dir, unsigned offset)
+{
+#define blk (blockbuf->check_file_blk)
+ struct minix2_inode *inode;
+ int ino;
+ char *name;
+ int block;
+
+ block = map_block2(dir, offset / BLOCK_SIZE);
+ read_block(block, blk);
+ name = blk + (offset % BLOCK_SIZE) + 2;
+ ino = *(uint16_t *) (name - 2);
+ if (ino > INODES) {
+ printf("%s contains a bad inode number for file '%.*s'. ",
+ current_name, namelen, name);
+ if (ask("Remove", 1)) {
+ *(uint16_t *) (name - 2) = 0;
+ write_block(block, blk);
+ }
+ ino = 0;
+ }
+ push_filename(name);
+ inode = get_inode2(ino);
+ pop_filename();
+ if (!offset) {
+ if (inode && LONE_CHAR(name, '.'))
+ return;
+ printf("%s: bad directory: '.' isn't first\n", current_name);
+ errors_uncorrected = 1;
+ }
+ if (offset == dirsize) {
+ if (inode && strcmp("..", name) == 0)
+ return;
+ printf("%s: bad directory: '..' isn't second\n", current_name);
+ errors_uncorrected = 1;
+ }
+ if (!inode)
+ return;
+ push_filename(name);
+ if (list) {
+ if (verbose)
+ printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
+ printf("%s%s\n", current_name, S_ISDIR(inode->i_mode) ? ":" : "");
+ }
+ check_zones2(ino);
+ if (inode && S_ISDIR(inode->i_mode))
+ recursive_check2(ino);
+ pop_filename();
+#undef blk
+}
+#endif
+
+static void recursive_check(unsigned ino)
+{
+ struct minix1_inode *dir;
+ unsigned offset;
+
+ dir = Inode1 + ino;
+ if (!S_ISDIR(dir->i_mode))
+ die("internal error");
+ if (dir->i_size < 2 * dirsize) {
+ printf("%s: bad directory: size<32", current_name);
+ errors_uncorrected = 1;
+ }
+ for (offset = 0; offset < dir->i_size; offset += dirsize)
+ check_file(dir, offset);
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void recursive_check2(unsigned ino)
+{
+ struct minix2_inode *dir;
+ unsigned offset;
+
+ dir = Inode2 + ino;
+ if (!S_ISDIR(dir->i_mode))
+ die("internal error");
+ if (dir->i_size < 2 * dirsize) {
+ printf("%s: bad directory: size<32", current_name);
+ errors_uncorrected = 1;
+ }
+ for (offset = 0; offset < dir->i_size; offset += dirsize)
+ check_file2(dir, offset);
+}
+#endif
+
+static int bad_zone(int i)
+{
+ char buffer[BLOCK_SIZE];
+
+ if (BLOCK_SIZE * i != lseek(IN, BLOCK_SIZE * i, SEEK_SET))
+ die("seek failed in bad_zone");
+ return (BLOCK_SIZE != read(IN, buffer, BLOCK_SIZE));
+}
+
+static void check_counts(void)
+{
+ int i;
+
+ for (i = 1; i <= INODES; i++) {
+ if (warn_mode && Inode1[i].i_mode && !inode_in_use(i)) {
+ printf("Inode %d has non-zero mode. ", i);
+ if (ask("Clear", 1)) {
+ Inode1[i].i_mode = 0;
+ changed = 1;
+ }
+ }
+ if (!inode_count[i]) {
+ if (!inode_in_use(i))
+ continue;
+ printf("Unused inode %d is marked as 'used' in the bitmap. ", i);
+ if (ask("Clear", 1))
+ unmark_inode(i);
+ continue;
+ }
+ if (!inode_in_use(i)) {
+ printf("Inode %d is used, but marked as 'unused' in the bitmap. ", i);
+ if (ask("Set", 1))
+ mark_inode(i);
+ }
+ if (Inode1[i].i_nlinks != inode_count[i]) {
+ printf("Inode %d (mode=%07o), i_nlinks=%d, counted=%d. ",
+ i, Inode1[i].i_mode, Inode1[i].i_nlinks,
+ inode_count[i]);
+ if (ask("Set i_nlinks to count", 1)) {
+ Inode1[i].i_nlinks = inode_count[i];
+ changed = 1;
+ }
+ }
+ }
+ for (i = FIRSTZONE; i < ZONES; i++) {
+ if ((zone_in_use(i) != 0) == zone_count[i])
+ continue;
+ if (!zone_count[i]) {
+ if (bad_zone(i))
+ continue;
+ printf("Zone %d is marked 'in use', but no file uses it. ", i);
+ if (ask("Unmark", 1))
+ unmark_zone(i);
+ continue;
+ }
+ printf("Zone %d: %sin use, counted=%d\n",
+ i, zone_in_use(i) ? "" : "not ", zone_count[i]);
+ }
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void check_counts2(void)
+{
+ int i;
+
+ for (i = 1; i <= INODES; i++) {
+ if (warn_mode && Inode2[i].i_mode && !inode_in_use(i)) {
+ printf("Inode %d has non-zero mode. ", i);
+ if (ask("Clear", 1)) {
+ Inode2[i].i_mode = 0;
+ changed = 1;
+ }
+ }
+ if (!inode_count[i]) {
+ if (!inode_in_use(i))
+ continue;
+ printf("Unused inode %d is marked as 'used' in the bitmap. ", i);
+ if (ask("Clear", 1))
+ unmark_inode(i);
+ continue;
+ }
+ if (!inode_in_use(i)) {
+ printf("Inode %d is used, but marked as 'unused' in the bitmap. ", i);
+ if (ask("Set", 1))
+ mark_inode(i);
+ }
+ if (Inode2[i].i_nlinks != inode_count[i]) {
+ printf("Inode %d (mode=%07o), i_nlinks=%d, counted=%d. ",
+ i, Inode2[i].i_mode, Inode2[i].i_nlinks,
+ inode_count[i]);
+ if (ask("Set i_nlinks to count", 1)) {
+ Inode2[i].i_nlinks = inode_count[i];
+ changed = 1;
+ }
+ }
+ }
+ for (i = FIRSTZONE; i < ZONES; i++) {
+ if ((zone_in_use(i) != 0) == zone_count[i])
+ continue;
+ if (!zone_count[i]) {
+ if (bad_zone(i))
+ continue;
+ printf("Zone %d is marked 'in use', but no file uses it. ", i);
+ if (ask("Unmark", 1))
+ unmark_zone(i);
+ continue;
+ }
+ printf("Zone %d: %sin use, counted=%d\n",
+ i, zone_in_use(i) ? "" : "not ", zone_count[i]);
+ }
+}
+#endif
+
+static void check(void)
+{
+ memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
+ memset(zone_count, 0, ZONES * sizeof(*zone_count));
+ check_zones(MINIX_ROOT_INO);
+ recursive_check(MINIX_ROOT_INO);
+ check_counts();
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void check2(void)
+{
+ memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
+ memset(zone_count, 0, ZONES * sizeof(*zone_count));
+ check_zones2(MINIX_ROOT_INO);
+ recursive_check2(MINIX_ROOT_INO);
+ check_counts2();
+}
+#else
+void check2(void);
+#endif
+
+int fsck_minix_main(int argc, char **argv);
+int fsck_minix_main(int argc, char **argv)
+{
+ struct termios tmp;
+ int retcode = 0;
+
+ xfunc_error_retval = 8;
+ blockbuf = xzalloc(sizeof(*blockbuf));
+
+ alloc_current_name();
+#if ENABLE_FEATURE_CLEAN_UP
+ /* Don't bother to free memory. Exit does
+ * that automagically, so we can save a few bytes */
+ atexit(free_current_name);
+#endif
+
+ if (INODE_SIZE1 * MINIX1_INODES_PER_BLOCK != BLOCK_SIZE)
+ die("bad inode size");
+#if ENABLE_FEATURE_MINIX2
+ if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
+ die("bad v2 inode size");
+#endif
+ while (--argc != 0) {
+ argv++;
+ if (argv[0][0] != '-') {
+ if (device_name)
+ bb_show_usage();
+ device_name = argv[0];
+ } else {
+ while (*++argv[0]) {
+ switch (argv[0][0]) {
+ case 'l':
+ list = 1;
+ break;
+ case 'a':
+ automatic = 1;
+ repair = 1;
+ break;
+ case 'r':
+ automatic = 0;
+ repair = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 's':
+ show = 1;
+ break;
+ case 'm':
+ warn_mode = 1;
+ break;
+ case 'f':
+ force = 1;
+ break;
+ default:
+ bb_show_usage();
+ }
+ }
+ }
+ }
+ if (!device_name)
+ bb_show_usage();
+
+ check_mount(); /* trying to check a mounted filesystem? */
+ if (repair && !automatic) {
+ if (!isatty(0) || !isatty(1))
+ die("need terminal for interactive repairs");
+ }
+ IN = xopen(device_name, repair ? O_RDWR : O_RDONLY);
+
+ /*sync(); paranoia? */
+ read_superblock();
+
+ /*
+ * Determine whether or not we should continue with the checking.
+ * This is based on the status of the filesystem valid and error
+ * flags and whether or not the -f switch was specified on the
+ * command line.
+ */
+ printf("%s, "PROGRAM_VERSION"\n", applet_name);
+
+ if (!(Super.s_state & MINIX_ERROR_FS)
+ && (Super.s_state & MINIX_VALID_FS) && !force
+ ) {
+ if (repair)
+ printf("%s is clean, check is skipped\n", device_name);
+ return 0;
+ } else if (force)
+ printf("Forcing filesystem check on %s\n", device_name);
+ else if (repair)
+ printf("Filesystem on %s is dirty, needs checking\n",
+ device_name);
+
+ read_tables();
+
+ if (repair && !automatic) {
+ tcgetattr(0, &termios);
+ tmp = termios;
+ tmp.c_lflag &= ~(ICANON | ECHO);
+ tcsetattr(0, TCSANOW, &tmp);
+ termios_set = 1;
+ }
+
+ if (version2) {
+ check_root2();
+ check2();
+ } else {
+ check_root();
+ check();
+ }
+
+ if (verbose) {
+ int i, free_cnt;
+
+ for (i = 1, free_cnt = 0; i <= INODES; i++)
+ if (!inode_in_use(i))
+ free_cnt++;
+ printf("\n%6u inodes used (%u%%)\n", (INODES - free_cnt),
+ 100 * (INODES - free_cnt) / INODES);
+ for (i = FIRSTZONE, free_cnt = 0; i < ZONES; i++)
+ if (!zone_in_use(i))
+ free_cnt++;
+ printf("%6u zones used (%u%%)\n\n"
+ "%6u regular files\n"
+ "%6u directories\n"
+ "%6u character device files\n"
+ "%6u block device files\n"
+ "%6u links\n"
+ "%6u symbolic links\n"
+ "------\n"
+ "%6u files\n",
+ (ZONES - free_cnt), 100 * (ZONES - free_cnt) / ZONES,
+ regular, directory, chardev, blockdev,
+ links - 2 * directory + 1, symlinks,
+ total - 2 * directory + 1);
+ }
+ if (changed) {
+ write_tables();
+ printf("FILE SYSTEM HAS BEEN CHANGED\n");
+ sync();
+ } else if (repair)
+ write_super_block();
+
+ if (repair && !automatic)
+ tcsetattr(0, TCSANOW, &termios);
+
+ if (changed)
+ retcode += 3;
+ if (errors_uncorrected)
+ retcode += 4;
+ return retcode;
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/getopt.c b/i/pc104/initrd/conf/busybox/util-linux/getopt.c
new file mode 100644
index 0000000..4861990
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/getopt.c
@@ -0,0 +1,366 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * getopt.c - Enhanced implementation of BSD getopt(1)
+ * Copyright (c) 1997, 1998, 1999, 2000 Frodo Looijaard <frodol@dds.nl>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/*
+ * Version 1.0-b4: Tue Sep 23 1997. First public release.
+ * Version 1.0: Wed Nov 19 1997.
+ * Bumped up the version number to 1.0
+ * Fixed minor typo (CSH instead of TCSH)
+ * Version 1.0.1: Tue Jun 3 1998
+ * Fixed sizeof instead of strlen bug
+ * Bumped up the version number to 1.0.1
+ * Version 1.0.2: Thu Jun 11 1998 (not present)
+ * Fixed gcc-2.8.1 warnings
+ * Fixed --version/-V option (not present)
+ * Version 1.0.5: Tue Jun 22 1999
+ * Make -u option work (not present)
+ * Version 1.0.6: Tue Jun 27 2000
+ * No important changes
+ * Version 1.1.0: Tue Jun 30 2000
+ * Added NLS support (partly written by Arkadiusz Mi<B6>kiewicz
+ * <misiek@misiek.eu.org>)
+ * Ported to Busybox - Alfred M. Szmidt <ams@trillian.itslinux.org>
+ * Removed --version/-V and --help/-h in
+ * Removed parse_error(), using bb_error_msg() from Busybox instead
+ * Replaced our_malloc with xmalloc and our_realloc with xrealloc
+ *
+ */
+
+#include "busybox.h"
+#include <getopt.h>
+
+/* NON_OPT is the code that is returned when a non-option is found in '+'
+ mode */
+enum {
+ NON_OPT = 1,
+/* LONG_OPT is the code that is returned when a long option is found. */
+ LONG_OPT = 2
+};
+
+/* The shells recognized. */
+typedef enum {BASH,TCSH} shell_t;
+
+
+/* Some global variables that tells us how to parse. */
+static shell_t shell=BASH; /* The shell we generate output for. */
+static int quiet_errors; /* 0 is not quiet. */
+static int quiet_output; /* 0 is not quiet. */
+static int quote=1; /* 1 is do quote. */
+static int alternative; /* 0 is getopt_long, 1 is getopt_long_only */
+
+/* Function prototypes */
+static const char *normalize(const char *arg);
+static int generate_output(char * argv[],int argc,const char *optstr,
+ const struct option *longopts);
+static void add_long_options(char *options);
+static void add_longopt(const char *name,int has_arg);
+static void set_shell(const char *new_shell);
+
+
+/*
+ * This function 'normalizes' a single argument: it puts single quotes around
+ * it and escapes other special characters. If quote is false, it just
+ * returns its argument.
+ * Bash only needs special treatment for single quotes; tcsh also recognizes
+ * exclamation marks within single quotes, and nukes whitespace.
+ * This function returns a pointer to a buffer that is overwritten by
+ * each call.
+ */
+const char *normalize(const char *arg)
+{
+ static char *BUFFER=NULL;
+ const char *argptr=arg;
+ char *bufptr;
+
+ free(BUFFER);
+
+ if (!quote) { /* Just copy arg */
+ BUFFER=xstrdup(arg);
+ return BUFFER;
+ }
+
+ /* Each character in arg may take up to four characters in the result:
+ For a quote we need a closing quote, a backslash, a quote and an
+ opening quote! We need also the global opening and closing quote,
+ and one extra character for '\0'. */
+ BUFFER=xmalloc(strlen(arg)*4+3);
+
+ bufptr=BUFFER;
+ *bufptr++='\'';
+
+ while (*argptr) {
+ if (*argptr == '\'') {
+ /* Quote: replace it with: '\'' */
+ *bufptr++='\'';
+ *bufptr++='\\';
+ *bufptr++='\'';
+ *bufptr++='\'';
+ } else if (shell==TCSH && *argptr=='!') {
+ /* Exclamation mark: replace it with: \! */
+ *bufptr++='\'';
+ *bufptr++='\\';
+ *bufptr++='!';
+ *bufptr++='\'';
+ } else if (shell==TCSH && *argptr=='\n') {
+ /* Newline: replace it with: \n */
+ *bufptr++='\\';
+ *bufptr++='n';
+ } else if (shell==TCSH && isspace(*argptr)) {
+ /* Non-newline whitespace: replace it with \<ws> */
+ *bufptr++='\'';
+ *bufptr++='\\';
+ *bufptr++=*argptr;
+ *bufptr++='\'';
+ } else
+ /* Just copy */
+ *bufptr++=*argptr;
+ argptr++;
+ }
+ *bufptr++='\'';
+ *bufptr++='\0';
+ return BUFFER;
+}
+
+/*
+ * Generate the output. argv[0] is the program name (used for reporting errors).
+ * argv[1..] contains the options to be parsed. argc must be the number of
+ * elements in argv (ie. 1 if there are no options, only the program name),
+ * optstr must contain the short options, and longopts the long options.
+ * Other settings are found in global variables.
+ */
+int generate_output(char * argv[],int argc,const char *optstr,
+ const struct option *longopts)
+{
+ int exit_code = 0; /* We assume everything will be OK */
+ int opt;
+ int longindex;
+ const char *charptr;
+
+ if (quiet_errors) /* No error reporting from getopt(3) */
+ opterr=0;
+ optind=0; /* Reset getopt(3) */
+
+ while ((opt = (alternative?
+ getopt_long_only(argc,argv,optstr,longopts,&longindex):
+ getopt_long(argc,argv,optstr,longopts,&longindex)))
+ != EOF)
+ if (opt == '?' || opt == ':' )
+ exit_code = 1;
+ else if (!quiet_output) {
+ if (opt == LONG_OPT) {
+ printf(" --%s",longopts[longindex].name);
+ if (longopts[longindex].has_arg)
+ printf(" %s",
+ normalize(optarg?optarg:""));
+ } else if (opt == NON_OPT)
+ printf(" %s",normalize(optarg));
+ else {
+ printf(" -%c",opt);
+ charptr = strchr(optstr,opt);
+ if (charptr != NULL && *++charptr == ':')
+ printf(" %s",
+ normalize(optarg?optarg:""));
+ }
+ }
+
+ if (! quiet_output) {
+ printf(" --");
+ while (optind < argc)
+ printf(" %s",normalize(argv[optind++]));
+ puts("");
+ }
+ return exit_code;
+}
+
+static struct option *long_options;
+static int long_options_length; /* Length of array */
+static int long_options_nr; /* Nr of used elements in array */
+enum { LONG_OPTIONS_INCR = 10 };
+#define init_longopt() add_longopt(NULL,0)
+
+/* Register a long option. The contents of name is copied. */
+void add_longopt(const char *name, int has_arg)
+{
+ if (!name) { /* init */
+ free(long_options);
+ long_options=NULL;
+ long_options_length=0;
+ long_options_nr=0;
+ }
+
+ if (long_options_nr == long_options_length) {
+ long_options_length += LONG_OPTIONS_INCR;
+ long_options=xrealloc(long_options,
+ sizeof(struct option) *
+ long_options_length);
+ }
+
+ long_options[long_options_nr].name=NULL;
+ long_options[long_options_nr].has_arg=0;
+ long_options[long_options_nr].flag=NULL;
+ long_options[long_options_nr].val=0;
+
+ if (long_options_nr) { /* Not for init! */
+ long_options[long_options_nr-1].has_arg=has_arg;
+ long_options[long_options_nr-1].flag=NULL;
+ long_options[long_options_nr-1].val=LONG_OPT;
+ long_options[long_options_nr-1].name=xstrdup(name);
+ }
+ long_options_nr++;
+}
+
+
+/*
+ * Register several long options. options is a string of long options,
+ * separated by commas or whitespace.
+ * This nukes options!
+ */
+void add_long_options(char *options)
+{
+ int arg_opt, tlen;
+ char *tokptr=strtok(options,", \t\n");
+ while (tokptr) {
+ arg_opt=no_argument;
+ tlen=strlen(tokptr);
+ if (tlen > 0) {
+ if (tokptr[tlen-1] == ':') {
+ if (tlen > 1 && tokptr[tlen-2] == ':') {
+ tokptr[tlen-2]='\0';
+ tlen -= 2;
+ arg_opt=optional_argument;
+ } else {
+ tokptr[tlen-1]='\0';
+ tlen -= 1;
+ arg_opt=required_argument;
+ }
+ if (tlen == 0)
+ bb_error_msg("empty long option after -l or --long argument");
+ }
+ add_longopt(tokptr,arg_opt);
+ }
+ tokptr=strtok(NULL,", \t\n");
+ }
+}
+
+void set_shell(const char *new_shell)
+{
+ if (!strcmp(new_shell,"bash"))
+ shell=BASH;
+ else if (!strcmp(new_shell,"tcsh"))
+ shell=TCSH;
+ else if (!strcmp(new_shell,"sh"))
+ shell=BASH;
+ else if (!strcmp(new_shell,"csh"))
+ shell=TCSH;
+ else
+ bb_error_msg("unknown shell after -s or --shell argument");
+}
+
+
+/* Exit codes:
+ * 0) No errors, successful operation.
+ * 1) getopt(3) returned an error.
+ * 2) A problem with parameter parsing for getopt(1).
+ * 3) Internal error, out of memory
+ * 4) Returned for -T
+ */
+
+static const struct option longopts[]=
+{
+ {"options",required_argument,NULL,'o'},
+ {"longoptions",required_argument,NULL,'l'},
+ {"quiet",no_argument,NULL,'q'},
+ {"quiet-output",no_argument,NULL,'Q'},
+ {"shell",required_argument,NULL,'s'},
+ {"test",no_argument,NULL,'T'},
+ {"unquoted",no_argument,NULL,'u'},
+ {"alternative",no_argument,NULL,'a'},
+ {"name",required_argument,NULL,'n'},
+ {NULL,0,NULL,0}
+};
+
+/* Stop scanning as soon as a non-option argument is found! */
+static const char shortopts[]="+ao:l:n:qQs:Tu";
+
+
+int getopt_main(int argc, char *argv[]);
+int getopt_main(int argc, char *argv[])
+{
+ const char *optstr = NULL;
+ char *name = NULL;
+ int opt;
+ int compatible=0;
+
+ init_longopt();
+
+ if (getenv("GETOPT_COMPATIBLE"))
+ compatible=1;
+
+ if (argc == 1) {
+ if (compatible) {
+ /* For some reason, the original getopt gave no error
+ when there were no arguments. */
+ printf(" --\n");
+ return 0;
+ } else
+ bb_error_msg_and_die("missing optstring argument");
+ }
+
+ if (argv[1][0] != '-' || compatible) {
+ char *s;
+
+ quote=0;
+ s=xmalloc(strlen(argv[1])+1);
+ strcpy(s,argv[1]+strspn(argv[1],"-+"));
+ argv[1]=argv[0];
+ return generate_output(argv+1,argc-1,s,long_options);
+ }
+
+ while ((opt = getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF)
+ switch (opt) {
+ case 'a':
+ alternative=1;
+ break;
+ case 'o':
+ optstr = optarg;
+ break;
+ case 'l':
+ add_long_options(optarg);
+ break;
+ case 'n':
+ name = optarg;
+ break;
+ case 'q':
+ quiet_errors=1;
+ break;
+ case 'Q':
+ quiet_output=1;
+ break;
+ case 's':
+ set_shell(optarg);
+ break;
+ case 'T':
+ return 4;
+ case 'u':
+ quote=0;
+ break;
+ default:
+ bb_show_usage();
+ }
+
+ if (!optstr) {
+ if (optind >= argc)
+ bb_error_msg_and_die("missing optstring argument");
+ else optstr=argv[optind++];
+ }
+ if (name)
+ argv[optind-1]=name;
+ else
+ argv[optind-1]=argv[0];
+ return generate_output(argv+optind-1,argc-optind+1,optstr,long_options);
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/hexdump.c b/i/pc104/initrd/conf/busybox/util-linux/hexdump.c
new file mode 100644
index 0000000..cddd185
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/hexdump.c
@@ -0,0 +1,102 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * hexdump implementation for busybox
+ * Based on code from util-linux v 2.11l
+ *
+ * Copyright (c) 1989
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Licensed under GPLv2 or later, see file License in this tarball for details.
+ */
+
+#include "busybox.h"
+#include <getopt.h>
+#include "dump.h"
+
+static void bb_dump_addfile(char *name)
+{
+ char *p;
+ FILE *fp;
+ char *buf;
+
+ fp = xfopen(name, "r");
+
+ while ((buf = xmalloc_getline(fp)) != NULL) {
+ p = skip_whitespace(buf);
+
+ if (*p && (*p != '#')) {
+ bb_dump_add(p);
+ }
+ free(buf);
+ }
+ fclose(fp);
+}
+
+static const char * const add_strings[] = {
+ "\"%07.7_ax \" 16/1 \"%03o \" \"\\n\"", /* b */
+ "\"%07.7_ax \" 16/1 \"%3_c \" \"\\n\"", /* c */
+ "\"%07.7_ax \" 8/2 \" %05u \" \"\\n\"", /* d */
+ "\"%07.7_ax \" 8/2 \" %06o \" \"\\n\"", /* o */
+ "\"%07.7_ax \" 8/2 \" %04x \" \"\\n\"", /* x */
+};
+
+static const char add_first[] = "\"%07.7_Ax\n\"";
+
+static const char hexdump_opts[] = "bcdoxCe:f:n:s:v";
+
+static const struct suffix_mult suffixes[] = {
+ {"b", 512 },
+ {"k", 1024 },
+ {"m", 1024*1024 },
+ {NULL, 0 }
+};
+
+int hexdump_main(int argc, char **argv);
+int hexdump_main(int argc, char **argv)
+{
+ const char *p;
+ int ch;
+
+ bb_dump_vflag = FIRST;
+ bb_dump_length = -1;
+
+ while ((ch = getopt(argc, argv, hexdump_opts)) > 0) {
+ p = strchr(hexdump_opts, ch);
+ if (!p)
+ bb_show_usage();
+ if ((p - hexdump_opts) < 5) {
+ bb_dump_add(add_first);
+ bb_dump_add(add_strings[(int)(p - hexdump_opts)]);
+ } else if (ch == 'C') {
+ bb_dump_add("\"%08.8_Ax\n\"");
+ bb_dump_add("\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" ");
+ bb_dump_add("\" |\" 16/1 \"%_p\" \"|\\n\"");
+ } else {
+ /* Save a little bit of space below by omitting the 'else's. */
+ if (ch == 'e') {
+ bb_dump_add(optarg);
+ } /* else */
+ if (ch == 'f') {
+ bb_dump_addfile(optarg);
+ } /* else */
+ if (ch == 'n') {
+ bb_dump_length = xatoi_u(optarg);
+ } /* else */
+ if (ch == 's') {
+ bb_dump_skip = xatoul_range_sfx(optarg, 0, LONG_MAX, suffixes);
+ } /* else */
+ if (ch == 'v') {
+ bb_dump_vflag = ALL;
+ }
+ }
+ }
+
+ if (!bb_dump_fshead) {
+ bb_dump_add(add_first);
+ bb_dump_add("\"%07.7_ax \" 8/2 \"%04x \" \"\\n\"");
+ }
+
+ argv += optind;
+
+ return bb_dump_dump(argv);
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/hwclock.c b/i/pc104/initrd/conf/busybox/util-linux/hwclock.c
new file mode 100644
index 0000000..86235e9
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/hwclock.c
@@ -0,0 +1,222 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini hwclock implementation for busybox
+ *
+ * Copyright (C) 2002 Robert Griebl <griebl@gmx.de>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+*/
+
+
+#include <sys/ioctl.h>
+#include <sys/utsname.h>
+#include <getopt.h>
+#include "busybox.h"
+
+/* Copied from linux/rtc.h to eliminate the kernel dependency */
+struct linux_rtc_time {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+};
+
+#define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time) /* Set RTC time */
+#define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time) /* Read RTC time */
+
+#if ENABLE_FEATURE_HWCLOCK_LONG_OPTIONS
+# ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+# endif
+#endif
+
+static const char *rtcname;
+
+static int xopen_rtc(int flags)
+{
+ int rtc;
+
+ if (!rtcname) {
+ rtc = open("/dev/rtc", flags);
+ if (rtc >= 0)
+ return rtc;
+ rtc = open("/dev/rtc0", flags);
+ if (rtc >= 0)
+ return rtc;
+ rtcname = "/dev/misc/rtc";
+ }
+ return xopen(rtcname, flags);
+}
+
+static time_t read_rtc(int utc)
+{
+ struct tm tm;
+ char *oldtz = 0;
+ time_t t = 0;
+ int rtc = xopen_rtc(O_RDONLY);
+
+ memset(&tm, 0, sizeof(struct tm));
+ if (ioctl(rtc, RTC_RD_TIME, &tm) < 0 )
+ bb_perror_msg_and_die("cannot read time from RTC");
+ tm.tm_isdst = -1; /* not known */
+
+ close(rtc);
+
+ if (utc) {
+ oldtz = getenv("TZ");
+ setenv("TZ", "UTC 0", 1);
+ tzset();
+ }
+
+ t = mktime(&tm);
+
+ if (utc) {
+ if (oldtz)
+ setenv("TZ", oldtz, 1);
+ else
+ unsetenv("TZ");
+ tzset();
+ }
+ return t;
+}
+
+static void write_rtc(time_t t, int utc)
+{
+ struct tm tm;
+ int rtc = xopen_rtc(O_WRONLY);
+
+ tm = *(utc ? gmtime(&t) : localtime(&t));
+ tm.tm_isdst = 0;
+
+ if (ioctl(rtc, RTC_SET_TIME, &tm) < 0)
+ bb_perror_msg_and_die("cannot set the RTC time");
+
+ close(rtc);
+}
+
+static int show_clock(int utc)
+{
+ struct tm *ptm;
+ time_t t;
+ RESERVE_CONFIG_BUFFER(buffer, 64);
+
+ t = read_rtc(utc);
+ ptm = localtime(&t); /* Sets 'tzname[]' */
+
+ safe_strncpy(buffer, ctime(&t), 64);
+ if (buffer[0])
+ buffer[strlen(buffer) - 1] = 0;
+
+ //printf("%s %.6f seconds %s\n", buffer, 0.0, utc ? "" : (ptm->tm_isdst ? tzname[1] : tzname[0]));
+ printf( "%s %.6f seconds\n", buffer, 0.0);
+ RELEASE_CONFIG_BUFFER(buffer);
+
+ return 0;
+}
+
+static int to_sys_clock(int utc)
+{
+ struct timeval tv = { 0, 0 };
+ const struct timezone tz = { timezone/60 - 60*daylight, 0 };
+
+ tv.tv_sec = read_rtc(utc);
+
+ if (settimeofday(&tv, &tz))
+ bb_perror_msg_and_die("settimeofday() failed");
+
+ return 0;
+}
+
+static int from_sys_clock(int utc)
+{
+ struct timeval tv = { 0, 0 };
+ struct timezone tz = { 0, 0 };
+
+ if (gettimeofday(&tv, &tz))
+ bb_perror_msg_and_die("gettimeofday() failed");
+
+ write_rtc(tv.tv_sec, utc);
+ return 0;
+}
+
+#ifdef CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS
+# define ADJTIME_PATH "/var/lib/hwclock/adjtime"
+#else
+# define ADJTIME_PATH "/etc/adjtime"
+#endif
+static int check_utc(void)
+{
+ int utc = 0;
+ FILE *f = fopen(ADJTIME_PATH, "r");
+
+ if (f) {
+ RESERVE_CONFIG_BUFFER(buffer, 128);
+
+ while (fgets(buffer, sizeof(buffer), f)) {
+ int len = strlen(buffer);
+
+ while (len && isspace(buffer[len - 1]))
+ len--;
+
+ buffer[len] = 0;
+
+ if (strncmp(buffer, "UTC", 3) == 0 ) {
+ utc = 1;
+ break;
+ }
+ }
+ fclose(f);
+ RELEASE_CONFIG_BUFFER(buffer);
+ }
+ return utc;
+}
+
+#define HWCLOCK_OPT_LOCALTIME 0x01
+#define HWCLOCK_OPT_UTC 0x02
+#define HWCLOCK_OPT_SHOW 0x04
+#define HWCLOCK_OPT_HCTOSYS 0x08
+#define HWCLOCK_OPT_SYSTOHC 0x10
+#define HWCLOCK_OPT_RTCFILE 0x20
+
+int hwclock_main(int argc, char **argv );
+int hwclock_main(int argc, char **argv )
+{
+ unsigned opt;
+ int utc;
+
+#if ENABLE_FEATURE_HWCLOCK_LONG_OPTIONS
+ static const struct option hwclock_long_options[] = {
+ { "localtime", 0, 0, 'l' },
+ { "utc", 0, 0, 'u' },
+ { "show", 0, 0, 'r' },
+ { "hctosys", 0, 0, 's' },
+ { "systohc", 0, 0, 'w' },
+ { "file", 1, 0, 'f' },
+ { 0, 0, 0, 0 }
+ };
+ applet_long_options = hwclock_long_options;
+#endif
+ opt_complementary = "?:r--ws:w--rs:s--wr:l--u:u--l";
+ opt = getopt32(argc, argv, "lurswf:", &rtcname);
+
+ /* If -u or -l wasn't given check if we are using utc */
+ if (opt & (HWCLOCK_OPT_UTC | HWCLOCK_OPT_LOCALTIME))
+ utc = opt & HWCLOCK_OPT_UTC;
+ else
+ utc = check_utc();
+
+ if (opt & HWCLOCK_OPT_HCTOSYS) {
+ return to_sys_clock(utc);
+ }
+ else if (opt & HWCLOCK_OPT_SYSTOHC) {
+ return from_sys_clock(utc);
+ } else {
+ /* default HWCLOCK_OPT_SHOW */
+ return show_clock(utc);
+ }
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/ipcrm.c b/i/pc104/initrd/conf/busybox/util-linux/ipcrm.c
new file mode 100644
index 0000000..9240e2c
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/ipcrm.c
@@ -0,0 +1,218 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ipcrm.c - utility to allow removal of IPC objects and data structures.
+ *
+ * 01 Sept 2004 - Rodney Radford <rradford@mindspring.com>
+ * Adapted for busybox from util-linux-2.12a.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "busybox.h"
+
+/* X/OPEN tells us to use <sys/{types,ipc,sem}.h> for semctl() */
+/* X/OPEN tells us to use <sys/{types,ipc,msg}.h> for msgctl() */
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+
+#if defined (__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
+/* union semun is defined by including <sys/sem.h> */
+#else
+/* according to X/OPEN we have to define it ourselves */
+union semun {
+ int val;
+ struct semid_ds *buf;
+ unsigned short int *array;
+ struct seminfo *__buf;
+};
+#endif
+
+#ifndef CONFIG_IPCRM_DROP_LEGACY
+
+typedef enum type_id {
+ SHM,
+ SEM,
+ MSG
+} type_id;
+
+static int remove_ids(type_id type, int argc, char **argv)
+{
+ unsigned long id;
+ int ret = 0; /* silence gcc */
+ int nb_errors = 0;
+ union semun arg;
+
+ arg.val = 0;
+
+ while (argc) {
+ id = bb_strtoul(argv[0], NULL, 10);
+ if (errno || id > INT_MAX) {
+ bb_error_msg("invalid id: %s", argv[0]);
+ nb_errors++;
+ } else {
+ if (type == SEM)
+ ret = semctl(id, 0, IPC_RMID, arg);
+ else if (type == MSG)
+ ret = msgctl(id, IPC_RMID, NULL);
+ else if (type == SHM)
+ ret = shmctl(id, IPC_RMID, NULL);
+
+ if (ret) {
+ bb_perror_msg("cannot remove id %s", argv[0]);
+ nb_errors++;
+ }
+ }
+ argc--;
+ argv++;
+ }
+
+ return nb_errors;
+}
+#endif /* #ifndef CONFIG_IPCRM_DROP_LEGACY */
+
+
+int ipcrm_main(int argc, char **argv);
+int ipcrm_main(int argc, char **argv)
+{
+ int c;
+ int error = 0;
+
+ /* if the command is executed without parameters, do nothing */
+ if (argc == 1)
+ return 0;
+#ifndef CONFIG_IPCRM_DROP_LEGACY
+ /* check to see if the command is being invoked in the old way if so
+ then run the old code. Valid commands are msg, shm, sem. */
+ {
+ type_id what = 0; /* silence gcc */
+ char w;
+
+ w=argv[1][0];
+ if ( ((w == 'm' && argv[1][1] == 's' && argv[1][2] == 'g')
+ || (argv[1][0] == 's'
+ && ((w=argv[1][1]) == 'h' || w == 'e')
+ && argv[1][2] == 'm')
+ ) && argv[1][3] == '\0'
+ ) {
+
+ if (argc < 3)
+ bb_show_usage();
+
+ if (w == 'h')
+ what = SHM;
+ else if (w == 'm')
+ what = MSG;
+ else if (w == 'e')
+ what = SEM;
+
+ if (remove_ids(what, argc-2, &argv[2]))
+ fflush_stdout_and_exit(1);
+ printf("resource(s) deleted\n");
+ return 0;
+ }
+ }
+#endif /* #ifndef CONFIG_IPCRM_DROP_LEGACY */
+
+ /* process new syntax to conform with SYSV ipcrm */
+ while ((c = getopt(argc, argv, "q:m:s:Q:M:S:h?")) != -1) {
+ int result;
+ int id = 0;
+ int iskey = (isupper)(c);
+
+ /* needed to delete semaphores */
+ union semun arg;
+
+ arg.val = 0;
+
+ if ((c == '?') || (c == 'h')) {
+ bb_show_usage();
+ }
+
+ /* we don't need case information any more */
+ c = tolower(c);
+
+ /* make sure the option is in range: allowed are q, m, s */
+ if (c != 'q' && c != 'm' && c != 's') {
+ bb_show_usage();
+ }
+
+ if (iskey) {
+ /* keys are in hex or decimal */
+ key_t key = xstrtoul(optarg, 0);
+
+ if (key == IPC_PRIVATE) {
+ error++;
+ bb_error_msg("illegal key (%s)", optarg);
+ continue;
+ }
+
+ /* convert key to id */
+ id = ((c == 'q') ? msgget(key, 0) :
+ (c == 'm') ? shmget(key, 0, 0) : semget(key, 0, 0));
+
+ if (id < 0) {
+ const char *errmsg;
+ const char *const what = "key";
+
+ error++;
+ switch (errno) {
+ case EACCES:
+ errmsg = "permission denied for";
+ break;
+ case EIDRM:
+ errmsg = "already removed";
+ break;
+ case ENOENT:
+ errmsg = "invalid";
+ break;
+ default:
+ errmsg = "unknown error in";
+ break;
+ }
+ bb_error_msg("%s %s (%s)", errmsg, what, optarg);
+ continue;
+ }
+ } else {
+ /* ids are in decimal */
+ id = xatoul(optarg);
+ }
+
+ result = ((c == 'q') ? msgctl(id, IPC_RMID, NULL) :
+ (c == 'm') ? shmctl(id, IPC_RMID, NULL) :
+ semctl(id, 0, IPC_RMID, arg));
+
+ if (result) {
+ const char *errmsg;
+ const char *const what = iskey ? "key" : "id";
+
+ error++;
+ switch (errno) {
+ case EACCES:
+ case EPERM:
+ errmsg = "permission denied for";
+ break;
+ case EINVAL:
+ errmsg = "invalid";
+ break;
+ case EIDRM:
+ errmsg = "already removed";
+ break;
+ default:
+ errmsg = "unknown error in";
+ break;
+ }
+ bb_error_msg("%s %s (%s)", errmsg, what, optarg);
+ continue;
+ }
+ }
+
+ /* print usage if we still have some arguments left over */
+ if (optind != argc) {
+ bb_show_usage();
+ }
+
+ /* exit value reflects the number of errors encountered */
+ return error;
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/ipcs.c b/i/pc104/initrd/conf/busybox/util-linux/ipcs.c
new file mode 100644
index 0000000..5a7b224
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/ipcs.c
@@ -0,0 +1,631 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ipcs.c -- provides information on allocated ipc resources.
+ *
+ * 01 Sept 2004 - Rodney Radford <rradford@mindspring.com>
+ * Adapted for busybox from util-linux-2.12a.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "busybox.h"
+#include <errno.h>
+#include <time.h>
+#include <pwd.h>
+#include <grp.h>
+
+/* X/OPEN tells us to use <sys/{types,ipc,sem}.h> for semctl() */
+/* X/OPEN tells us to use <sys/{types,ipc,msg}.h> for msgctl() */
+/* X/OPEN tells us to use <sys/{types,ipc,shm}.h> for shmctl() */
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/msg.h>
+#include <sys/shm.h>
+
+
+
+/*-------------------------------------------------------------------*/
+/* SHM_DEST and SHM_LOCKED are defined in kernel headers,
+ but inside #ifdef __KERNEL__ ... #endif */
+#ifndef SHM_DEST
+/* shm_mode upper byte flags */
+#define SHM_DEST 01000 /* segment will be destroyed on last detach */
+#define SHM_LOCKED 02000 /* segment will not be swapped */
+#endif
+
+/* For older kernels the same holds for the defines below */
+#ifndef MSG_STAT
+#define MSG_STAT 11
+#define MSG_INFO 12
+#endif
+
+#ifndef SHM_STAT
+#define SHM_STAT 13
+#define SHM_INFO 14
+struct shm_info {
+ int used_ids;
+ ulong shm_tot; /* total allocated shm */
+ ulong shm_rss; /* total resident shm */
+ ulong shm_swp; /* total swapped shm */
+ ulong swap_attempts;
+ ulong swap_successes;
+};
+#endif
+
+#ifndef SEM_STAT
+#define SEM_STAT 18
+#define SEM_INFO 19
+#endif
+
+/* Some versions of libc only define IPC_INFO when __USE_GNU is defined. */
+#ifndef IPC_INFO
+#define IPC_INFO 3
+#endif
+/*-------------------------------------------------------------------*/
+
+/* The last arg of semctl is a union semun, but where is it defined?
+ X/OPEN tells us to define it ourselves, but until recently
+ Linux include files would also define it. */
+#if defined (__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
+/* union semun is defined by including <sys/sem.h> */
+#else
+/* according to X/OPEN we have to define it ourselves */
+union semun {
+ int val;
+ struct semid_ds *buf;
+ unsigned short int *array;
+ struct seminfo *__buf;
+};
+#endif
+
+/* X/OPEN (Jan 1987) does not define fields key, seq in struct ipc_perm;
+ libc 4/5 does not mention struct ipc_term at all, but includes
+ <linux/ipc.h>, which defines a struct ipc_perm with such fields.
+ glibc-1.09 has no support for sysv ipc.
+ glibc 2 uses __key, __seq */
+#if defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1
+#define KEY __key
+#else
+#define KEY key
+#endif
+
+#define LIMITS 1
+#define STATUS 2
+#define CREATOR 3
+#define TIME 4
+#define PID 5
+
+static char format;
+
+static void print_perms(int id, struct ipc_perm *ipcp)
+{
+ struct passwd *pw;
+ struct group *gr;
+
+ printf("%-10d %-10o", id, ipcp->mode & 0777);
+
+ if ((pw = getpwuid(ipcp->cuid)))
+ printf(" %-10s", pw->pw_name);
+ else
+ printf(" %-10d", ipcp->cuid);
+ if ((gr = getgrgid(ipcp->cgid)))
+ printf(" %-10s", gr->gr_name);
+ else
+ printf(" %-10d", ipcp->cgid);
+
+ if ((pw = getpwuid(ipcp->uid)))
+ printf(" %-10s", pw->pw_name);
+ else
+ printf(" %-10d", ipcp->uid);
+ if ((gr = getgrgid(ipcp->gid)))
+ printf(" %-10s\n", gr->gr_name);
+ else
+ printf(" %-10d\n", ipcp->gid);
+}
+
+
+static void do_shm(void)
+{
+ int maxid, shmid, id;
+ struct shmid_ds shmseg;
+ struct shm_info shm_info;
+ struct shminfo shminfo;
+ struct ipc_perm *ipcp = &shmseg.shm_perm;
+ struct passwd *pw;
+
+ maxid = shmctl(0, SHM_INFO, (struct shmid_ds *) (void *) &shm_info);
+ if (maxid < 0) {
+ printf("kernel not configured for %s\n", "shared memory");
+ return;
+ }
+
+ switch (format) {
+ case LIMITS:
+ printf("------ Shared Memory %s --------\n", "Limits");
+ if ((shmctl(0, IPC_INFO, (struct shmid_ds *) (void *) &shminfo)) < 0)
+ return;
+ /* glibc 2.1.3 and all earlier libc's have ints as fields
+ of struct shminfo; glibc 2.1.91 has unsigned long; ach */
+ printf("max number of segments = %lu\n"
+ "max seg size (kbytes) = %lu\n"
+ "max total shared memory (pages) = %lu\n"
+ "min seg size (bytes) = %lu\n",
+ (unsigned long) shminfo.shmmni,
+ (unsigned long) (shminfo.shmmax >> 10),
+ (unsigned long) shminfo.shmall,
+ (unsigned long) shminfo.shmmin);
+ return;
+
+ case STATUS:
+ printf("------ Shared Memory %s --------\n", "Status");
+ printf( "segments allocated %d\n"
+ "pages allocated %ld\n"
+ "pages resident %ld\n"
+ "pages swapped %ld\n"
+ "Swap performance: %ld attempts\t%ld successes\n",
+ shm_info.used_ids,
+ shm_info.shm_tot,
+ shm_info.shm_rss,
+ shm_info.shm_swp,
+ shm_info.swap_attempts, shm_info.swap_successes);
+ return;
+
+ case CREATOR:
+ printf("------ Shared Memory %s --------\n", "Segment Creators/Owners");
+ printf( "%-10s %-10s %-10s %-10s %-10s %-10s\n",
+ "shmid", "perms", "cuid", "cgid", "uid", "gid");
+ break;
+
+ case TIME:
+ printf("------ Shared Memory %s --------\n", "Attach/Detach/Change Times");
+ printf( "%-10s %-10s %-20s %-20s %-20s\n",
+ "shmid", "owner", "attached", "detached", "changed");
+ break;
+
+ case PID:
+ printf("------ Shared Memory %s --------\n", "Creator/Last-op");
+ printf( "%-10s %-10s %-10s %-10s\n",
+ "shmid", "owner", "cpid", "lpid");
+ break;
+
+ default:
+ printf("------ Shared Memory %s --------\n", "Segments");
+ printf( "%-10s %-10s %-10s %-10s %-10s %-10s %-12s\n",
+ "key", "shmid", "owner", "perms", "bytes", "nattch",
+ "status");
+ break;
+ }
+
+ for (id = 0; id <= maxid; id++) {
+ shmid = shmctl(id, SHM_STAT, &shmseg);
+ if (shmid < 0)
+ continue;
+ if (format == CREATOR) {
+ print_perms(shmid, ipcp);
+ continue;
+ }
+ pw = getpwuid(ipcp->uid);
+ switch (format) {
+ case TIME:
+ if (pw)
+ printf("%-10d %-10.10s", shmid, pw->pw_name);
+ else
+ printf("%-10d %-10d", shmid, ipcp->uid);
+ /* ctime uses static buffer: use separate calls */
+ printf(" %-20.16s", shmseg.shm_atime
+ ? ctime(&shmseg.shm_atime) + 4 : "Not set");
+ printf(" %-20.16s", shmseg.shm_dtime
+ ? ctime(&shmseg.shm_dtime) + 4 : "Not set");
+ printf(" %-20.16s\n", shmseg.shm_ctime
+ ? ctime(&shmseg.shm_ctime) + 4 : "Not set");
+ break;
+ case PID:
+ if (pw)
+ printf("%-10d %-10.10s", shmid, pw->pw_name);
+ else
+ printf("%-10d %-10d", shmid, ipcp->uid);
+ printf(" %-10d %-10d\n", shmseg.shm_cpid, shmseg.shm_lpid);
+ break;
+
+ default:
+ printf("0x%08x ", ipcp->KEY);
+ if (pw)
+ printf("%-10d %-10.10s", shmid, pw->pw_name);
+ else
+ printf("%-10d %-10d", shmid, ipcp->uid);
+ printf(" %-10o %-10lu %-10ld %-6s %-6s\n", ipcp->mode & 0777,
+ /*
+ * earlier: int, Austin has size_t
+ */
+ (unsigned long) shmseg.shm_segsz,
+ /*
+ * glibc-2.1.3 and earlier has unsigned short;
+ * Austin has shmatt_t
+ */
+ (long) shmseg.shm_nattch,
+ ipcp->mode & SHM_DEST ? "dest" : " ",
+ ipcp->mode & SHM_LOCKED ? "locked" : " ");
+ break;
+ }
+ }
+}
+
+
+static void do_sem(void)
+{
+ int maxid, semid, id;
+ struct semid_ds semary;
+ struct seminfo seminfo;
+ struct ipc_perm *ipcp = &semary.sem_perm;
+ struct passwd *pw;
+ union semun arg;
+
+ arg.array = (ushort *) (void *) &seminfo;
+ maxid = semctl(0, 0, SEM_INFO, arg);
+ if (maxid < 0) {
+ printf("kernel not configured for %s\n", "semaphores");
+ return;
+ }
+
+ switch (format) {
+ case LIMITS:
+ printf("------ Semaphore %s --------\n", "Limits");
+ arg.array = (ushort *) (void *) &seminfo; /* damn union */
+ if ((semctl(0, 0, IPC_INFO, arg)) < 0)
+ return;
+ printf("max number of arrays = %d\n"
+ "max semaphores per array = %d\n"
+ "max semaphores system wide = %d\n"
+ "max ops per semop call = %d\n"
+ "semaphore max value = %d\n",
+ seminfo.semmni,
+ seminfo.semmsl,
+ seminfo.semmns, seminfo.semopm, seminfo.semvmx);
+ return;
+
+ case STATUS:
+ printf("------ Semaphore %s --------\n", "Status");
+ printf( "used arrays = %d\n"
+ "allocated semaphores = %d\n",
+ seminfo.semusz, seminfo.semaem);
+ return;
+
+ case CREATOR:
+ printf("------ Semaphore %s --------\n", "Arrays Creators/Owners");
+ printf( "%-10s %-10s %-10s %-10s %-10s %-10s\n",
+ "semid", "perms", "cuid", "cgid", "uid", "gid");
+ break;
+
+ case TIME:
+ printf("------ Shared Memory %s --------\n", "Operation/Change Times");
+ printf( "%-8s %-10s %-26.24s %-26.24s\n",
+ "shmid", "owner", "last-op", "last-changed");
+ break;
+
+ case PID:
+ break;
+
+ default:
+ printf("------ Semaphore %s --------\n", "Arrays");
+ printf( "%-10s %-10s %-10s %-10s %-10s\n",
+ "key", "semid", "owner", "perms", "nsems");
+ break;
+ }
+
+ for (id = 0; id <= maxid; id++) {
+ arg.buf = (struct semid_ds *) &semary;
+ semid = semctl(id, 0, SEM_STAT, arg);
+ if (semid < 0)
+ continue;
+ if (format == CREATOR) {
+ print_perms(semid, ipcp);
+ continue;
+ }
+ pw = getpwuid(ipcp->uid);
+ switch (format) {
+ case TIME:
+ if (pw)
+ printf("%-8d %-10.10s", semid, pw->pw_name);
+ else
+ printf("%-8d %-10d", semid, ipcp->uid);
+ /* ctime uses static buffer: use separate calls */
+ printf(" %-26.24s", semary.sem_otime
+ ? ctime(&semary.sem_otime) : "Not set");
+ printf(" %-26.24s\n", semary.sem_ctime
+ ? ctime(&semary.sem_ctime) : "Not set");
+ break;
+ case PID:
+ break;
+
+ default:
+ printf("0x%08x ", ipcp->KEY);
+ if (pw)
+ printf("%-10d %-10.9s", semid, pw->pw_name);
+ else
+ printf("%-10d %-9d", semid, ipcp->uid);
+ printf(" %-10o %-10ld\n", ipcp->mode & 0777,
+ /*
+ * glibc-2.1.3 and earlier has unsigned short;
+ * glibc-2.1.91 has variation between
+ * unsigned short and unsigned long
+ * Austin prescribes unsigned short.
+ */
+ (long) semary.sem_nsems);
+ break;
+ }
+ }
+}
+
+
+static void do_msg(void)
+{
+ int maxid, msqid, id;
+ struct msqid_ds msgque;
+ struct msginfo msginfo;
+ struct ipc_perm *ipcp = &msgque.msg_perm;
+ struct passwd *pw;
+
+ maxid = msgctl(0, MSG_INFO, (struct msqid_ds *) (void *) &msginfo);
+ if (maxid < 0) {
+ printf("kernel not configured for %s\n", "message queues");
+ return;
+ }
+
+ switch (format) {
+ case LIMITS:
+ if ((msgctl(0, IPC_INFO, (struct msqid_ds *) (void *) &msginfo)) < 0)
+ return;
+ printf("------ Message%s --------\n", "s: Limits");
+ printf( "max queues system wide = %d\n"
+ "max size of message (bytes) = %d\n"
+ "default max size of queue (bytes) = %d\n",
+ msginfo.msgmni, msginfo.msgmax, msginfo.msgmnb);
+ return;
+
+ case STATUS:
+ printf("------ Message%s --------\n", "s: Status");
+ printf( "allocated queues = %d\n"
+ "used headers = %d\n"
+ "used space = %d bytes\n",
+ msginfo.msgpool, msginfo.msgmap, msginfo.msgtql);
+ return;
+
+ case CREATOR:
+ printf("------ Message%s --------\n", " Queues: Creators/Owners");
+ printf( "%-10s %-10s %-10s %-10s %-10s %-10s\n",
+ "msqid", "perms", "cuid", "cgid", "uid", "gid");
+ break;
+
+ case TIME:
+ printf("------ Message%s --------\n", " Queues Send/Recv/Change Times");
+ printf( "%-8s %-10s %-20s %-20s %-20s\n",
+ "msqid", "owner", "send", "recv", "change");
+ break;
+
+ case PID:
+ printf("------ Message%s --------\n", " Queues PIDs");
+ printf( "%-10s %-10s %-10s %-10s\n",
+ "msqid", "owner", "lspid", "lrpid");
+ break;
+
+ default:
+ printf("------ Message%s --------\n", " Queues");
+ printf( "%-10s %-10s %-10s %-10s %-12s %-12s\n",
+ "key", "msqid", "owner", "perms", "used-bytes", "messages");
+ break;
+ }
+
+ for (id = 0; id <= maxid; id++) {
+ msqid = msgctl(id, MSG_STAT, &msgque);
+ if (msqid < 0)
+ continue;
+ if (format == CREATOR) {
+ print_perms(msqid, ipcp);
+ continue;
+ }
+ pw = getpwuid(ipcp->uid);
+ switch (format) {
+ case TIME:
+ if (pw)
+ printf("%-8d %-10.10s", msqid, pw->pw_name);
+ else
+ printf("%-8d %-10d", msqid, ipcp->uid);
+ printf(" %-20.16s", msgque.msg_stime
+ ? ctime(&msgque.msg_stime) + 4 : "Not set");
+ printf(" %-20.16s", msgque.msg_rtime
+ ? ctime(&msgque.msg_rtime) + 4 : "Not set");
+ printf(" %-20.16s\n", msgque.msg_ctime
+ ? ctime(&msgque.msg_ctime) + 4 : "Not set");
+ break;
+ case PID:
+ if (pw)
+ printf("%-8d %-10.10s", msqid, pw->pw_name);
+ else
+ printf("%-8d %-10d", msqid, ipcp->uid);
+ printf(" %5d %5d\n", msgque.msg_lspid, msgque.msg_lrpid);
+ break;
+
+ default:
+ printf("0x%08x ", ipcp->KEY);
+ if (pw)
+ printf("%-10d %-10.10s", msqid, pw->pw_name);
+ else
+ printf("%-10d %-10d", msqid, ipcp->uid);
+ printf(" %-10o %-12ld %-12ld\n", ipcp->mode & 0777,
+ /*
+ * glibc-2.1.3 and earlier has unsigned short;
+ * glibc-2.1.91 has variation between
+ * unsigned short, unsigned long
+ * Austin has msgqnum_t
+ */
+ (long) msgque.msg_cbytes, (long) msgque.msg_qnum);
+ break;
+ }
+ }
+}
+
+
+static void print_shm(int shmid)
+{
+ struct shmid_ds shmds;
+ struct ipc_perm *ipcp = &shmds.shm_perm;
+
+ if (shmctl(shmid, IPC_STAT, &shmds) == -1) {
+ bb_perror_msg("shmctl");
+ return;
+ }
+
+ printf("\nShared memory Segment shmid=%d\n"
+ "uid=%d\tgid=%d\tcuid=%d\tcgid=%d\n"
+ "mode=%#o\taccess_perms=%#o\n"
+ "bytes=%ld\tlpid=%d\tcpid=%d\tnattch=%ld\n",
+ shmid,
+ ipcp->uid, ipcp->gid, ipcp->cuid, ipcp->cgid,
+ ipcp->mode, ipcp->mode & 0777,
+ (long) shmds.shm_segsz, shmds.shm_lpid, shmds.shm_cpid,
+ (long) shmds.shm_nattch);
+ printf("att_time=%-26.24s\n",
+ shmds.shm_atime ? ctime(&shmds.shm_atime) : "Not set");
+ printf("det_time=%-26.24s\n",
+ shmds.shm_dtime ? ctime(&shmds.shm_dtime) : "Not set");
+ printf("change_time=%-26.24s\n\n", ctime(&shmds.shm_ctime));
+}
+
+
+static void print_msg(int msqid)
+{
+ struct msqid_ds buf;
+ struct ipc_perm *ipcp = &buf.msg_perm;
+
+ if (msgctl(msqid, IPC_STAT, &buf) == -1) {
+ bb_perror_msg("msgctl");
+ return;
+ }
+
+ printf("\nMessage Queue msqid=%d\n"
+ "uid=%d\tgid=%d\tcuid=%d\tcgid=%d\tmode=%#o\n"
+ "cbytes=%ld\tqbytes=%ld\tqnum=%ld\tlspid=%d\tlrpid=%d\n",
+ msqid, ipcp->uid, ipcp->gid, ipcp->cuid, ipcp->cgid, ipcp->mode,
+ /*
+ * glibc-2.1.3 and earlier has unsigned short;
+ * glibc-2.1.91 has variation between
+ * unsigned short, unsigned long
+ * Austin has msgqnum_t (for msg_qbytes)
+ */
+ (long) buf.msg_cbytes, (long) buf.msg_qbytes,
+ (long) buf.msg_qnum, buf.msg_lspid, buf.msg_lrpid);
+
+ printf("send_time=%-26.24s\n",
+ buf.msg_stime ? ctime(&buf.msg_stime) : "Not set");
+ printf("rcv_time=%-26.24s\n",
+ buf.msg_rtime ? ctime(&buf.msg_rtime) : "Not set");
+ printf("change_time=%-26.24s\n\n",
+ buf.msg_ctime ? ctime(&buf.msg_ctime) : "Not set");
+}
+
+static void print_sem(int semid)
+{
+ struct semid_ds semds;
+ struct ipc_perm *ipcp = &semds.sem_perm;
+ union semun arg;
+ unsigned int i;
+
+ arg.buf = &semds;
+ if (semctl(semid, 0, IPC_STAT, arg)) {
+ bb_perror_msg("semctl");
+ return;
+ }
+
+ printf("\nSemaphore Array semid=%d\n"
+ "uid=%d\t gid=%d\t cuid=%d\t cgid=%d\n"
+ "mode=%#o, access_perms=%#o\n"
+ "nsems = %ld\n"
+ "otime = %-26.24s\n",
+ semid,
+ ipcp->uid, ipcp->gid, ipcp->cuid, ipcp->cgid,
+ ipcp->mode, ipcp->mode & 0777,
+ (long) semds.sem_nsems,
+ semds.sem_otime ? ctime(&semds.sem_otime) : "Not set");
+ printf("ctime = %-26.24s\n"
+ "%-10s %-10s %-10s %-10s %-10s\n",
+ ctime(&semds.sem_ctime),
+ "semnum", "value", "ncount", "zcount", "pid");
+
+ arg.val = 0;
+ for (i = 0; i < semds.sem_nsems; i++) {
+ int val, ncnt, zcnt, pid;
+
+ val = semctl(semid, i, GETVAL, arg);
+ ncnt = semctl(semid, i, GETNCNT, arg);
+ zcnt = semctl(semid, i, GETZCNT, arg);
+ pid = semctl(semid, i, GETPID, arg);
+ if (val < 0 || ncnt < 0 || zcnt < 0 || pid < 0) {
+ bb_perror_msg_and_die("semctl");
+ }
+ printf("%-10d %-10d %-10d %-10d %-10d\n", i, val, ncnt, zcnt, pid);
+ }
+ puts("");
+}
+
+int ipcs_main(int argc, char **argv);
+int ipcs_main(int argc, char **argv)
+{
+ int id = 0;
+ unsigned flags = 0;
+ unsigned opt;
+ char *opt_i;
+#define flag_print (1<<0)
+#define flag_msg (1<<1)
+#define flag_sem (1<<2)
+#define flag_shm (1<<3)
+
+ opt = getopt32(argc, argv, "i:aqsmtcplu", &opt_i);
+ if (opt & 0x1) { // -i
+ id = xatoi(opt_i);
+ flags |= flag_print;
+ }
+ if (opt & 0x2) flags |= flag_msg | flag_sem | flag_shm; // -a
+ if (opt & 0x4) flags |= flag_msg; // -q
+ if (opt & 0x8) flags |= flag_sem; // -s
+ if (opt & 0x10) flags |= flag_shm; // -m
+ if (opt & 0x20) format = TIME; // -t
+ if (opt & 0x40) format = CREATOR; // -c
+ if (opt & 0x80) format = PID; // -p
+ if (opt & 0x100) format = LIMITS; // -l
+ if (opt & 0x200) format = STATUS; // -u
+
+ if (flags & flag_print) {
+ if (flags & flag_shm) {
+ print_shm(id);
+ fflush_stdout_and_exit(0);
+ }
+ if (flags & flag_sem) {
+ print_sem(id);
+ fflush_stdout_and_exit(0);
+ }
+ if (flags & flag_msg) {
+ print_msg(id);
+ fflush_stdout_and_exit(0);
+ }
+ bb_show_usage();
+ }
+
+ if (!(flags & (flag_shm | flag_msg | flag_sem)))
+ flags |= flag_msg | flag_shm | flag_sem;
+ puts("");
+
+ if (flags & flag_shm) {
+ do_shm();
+ puts("");
+ }
+ if (flags & flag_sem) {
+ do_sem();
+ puts("");
+ }
+ if (flags & flag_msg) {
+ do_msg();
+ puts("");
+ }
+ fflush_stdout_and_exit(0);
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/losetup.c b/i/pc104/initrd/conf/busybox/util-linux/losetup.c
new file mode 100644
index 0000000..b220c98
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/losetup.c
@@ -0,0 +1,65 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini losetup implementation for busybox
+ *
+ * Copyright (C) 2002 Matt Kraai.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <getopt.h>
+#include <stdlib.h>
+
+#include "busybox.h"
+
+int losetup_main(int argc, char **argv);
+int losetup_main(int argc, char **argv)
+{
+ unsigned opt;
+ char *opt_o;
+ unsigned long long offset = 0;
+
+ opt = getopt32(argc, argv, "do:", &opt_o);
+ argc -= optind;
+ argv += optind;
+
+ if (opt == 0x3) // -d + -o (illegal)
+ bb_show_usage();
+
+ if (opt == 0x1) { // -d
+ /* detach takes exactly one argument */
+ if (argc != 1)
+ bb_show_usage();
+ if (!del_loop(argv[0]))
+ return EXIT_SUCCESS;
+ bb_perror_nomsg_and_die();
+ }
+
+ if (opt == 0x2) // -o
+ offset = xatoull(opt_o);
+
+ /* -o or no option */
+
+ if (argc == 2) {
+ if (set_loop(&argv[0], argv[1], offset) < 0)
+ bb_perror_nomsg_and_die();
+ } else if (argc == 1) {
+ char *s = query_loop(argv[0]);
+ if (!s) bb_perror_nomsg_and_die();
+ printf("%s: %s\n", argv[0], s);
+ if (ENABLE_FEATURE_CLEAN_UP) free(s);
+ } else {
+ char dev[sizeof(LOOP_NAME"0")] = LOOP_NAME"0";
+ char c;
+ for (c = '0'; c <= '9'; ++c) {
+ char *s;
+ dev[sizeof(LOOP_NAME"0")-2] = c;
+ s = query_loop(dev);
+ if (s) {
+ printf("%s: %s\n", dev, s);
+ if (ENABLE_FEATURE_CLEAN_UP) free(s);
+ }
+ }
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/mdev.c b/i/pc104/initrd/conf/busybox/util-linux/mdev.c
new file mode 100644
index 0000000..f9f067d
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/mdev.c
@@ -0,0 +1,270 @@
+/* vi: set sw=4 ts=4: */
+/*
+ *
+ * mdev - Mini udev for busybox
+ *
+ * Copyright 2005 Rob Landley <rob@landley.net>
+ * Copyright 2005 Frank Sorenson <frank@tuxrocks.com>
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+#include "busybox.h"
+#include "xregex.h"
+
+#define DEV_PATH "/dev"
+
+struct mdev_globals
+{
+ int root_major, root_minor;
+} mdev_globals;
+
+#define bbg mdev_globals
+
+/* mknod in /dev based on a path like "/sys/block/hda/hda1" */
+static void make_device(char *path, int delete)
+{
+ char *device_name;
+ int major, minor, type, len;
+ int mode = 0660;
+ uid_t uid = 0;
+ gid_t gid = 0;
+ char *temp = path + strlen(path);
+ char *command = NULL;
+
+ /* Try to read major/minor string. Note that the kernel puts \n after
+ * the data, so we don't need to worry about null terminating the string
+ * because sscanf() will stop at the first nondigit, which \n is. We
+ * also depend on path having writeable space after it. */
+
+ if (!delete) {
+ strcat(path, "/dev");
+ len = open_read_close(path, temp + 1, 64);
+ *temp++ = 0;
+ if (len < 1) return;
+ }
+
+ /* Determine device name, type, major and minor */
+
+ device_name = strrchr(path, '/') + 1;
+ type = path[5]=='c' ? S_IFCHR : S_IFBLK;
+
+ /* If we have a config file, look up permissions for this device */
+
+ if (ENABLE_FEATURE_MDEV_CONF) {
+ char *conf, *pos, *end;
+ int line, fd;
+
+ /* mmap the config file */
+ fd = open("/etc/mdev.conf", O_RDONLY);
+ if (fd < 0)
+ goto end_parse;
+ len = xlseek(fd, 0, SEEK_END);
+ conf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
+ close(fd);
+ if (!conf)
+ goto end_parse;
+
+ line = 0;
+ /* Loop through lines in mmaped file*/
+ for (pos=conf; pos-conf<len;) {
+ int field;
+ char *end2;
+
+ line++;
+ /* find end of this line */
+ for (end=pos; end-conf<len && *end!='\n'; end++)
+ ;
+
+ /* Three fields: regex, uid:gid, mode */
+ for (field=0; field < (3 + ENABLE_FEATURE_MDEV_EXEC);
+ field++)
+ {
+ /* Skip whitespace */
+ while (pos<end && isspace(*pos)) pos++;
+ if (pos==end || *pos=='#') break;
+ for (end2=pos;
+ end2<end && !isspace(*end2) && *end2!='#'; end2++)
+ ;
+
+ if (field == 0) {
+ /* Regex to match this device */
+
+ char *regex = strndupa(pos, end2-pos);
+ regex_t match;
+ regmatch_t off;
+ int result;
+
+ /* Is this it? */
+ xregcomp(&match,regex, REG_EXTENDED);
+ result = regexec(&match, device_name, 1, &off, 0);
+ regfree(&match);
+
+ /* If not this device, skip rest of line */
+ if (result || off.rm_so
+ || off.rm_eo != strlen(device_name))
+ break;
+ }
+ if (field == 1) {
+ /* uid:gid */
+
+ char *s, *s2;
+
+ /* Find : */
+ for (s=pos; s<end2 && *s!=':'; s++)
+ ;
+ if (s == end2) break;
+
+ /* Parse UID */
+ uid = strtoul(pos, &s2, 10);
+ if (s != s2) {
+ struct passwd *pass;
+ pass = getpwnam(strndupa(pos, s-pos));
+ if (!pass) break;
+ uid = pass->pw_uid;
+ }
+ s++;
+ /* parse GID */
+ gid = strtoul(s, &s2, 10);
+ if (end2 != s2) {
+ struct group *grp;
+ grp = getgrnam(strndupa(s, end2-s));
+ if (!grp) break;
+ gid = grp->gr_gid;
+ }
+ }
+ if (field == 2) {
+ /* mode */
+
+ mode = strtoul(pos, &pos, 8);
+ if (pos != end2) break;
+ }
+ if (ENABLE_FEATURE_MDEV_EXEC && field == 3) {
+ // Command to run
+ const char *s = "@$*";
+ const char *s2;
+ s2 = strchr(s, *pos++);
+ if (!s2) {
+ // Force error
+ field = 1;
+ break;
+ }
+ if ((s2-s+1) & (1<<delete))
+ command = xstrndup(pos, end-pos);
+ }
+
+ pos = end2;
+ }
+
+ /* Did everything parse happily? */
+
+ if (field > 2) break;
+ if (field) bb_error_msg_and_die("bad line %d",line);
+
+ /* Next line */
+ pos = ++end;
+ }
+ munmap(conf, len);
+ end_parse: /* nothing */ ;
+ }
+
+ umask(0);
+ if (!delete) {
+ if (sscanf(temp, "%d:%d", &major, &minor) != 2) return;
+ if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST)
+ bb_perror_msg_and_die("mknod %s", device_name);
+
+ if (major == bbg.root_major && minor == bbg.root_minor)
+ symlink(device_name, "root");
+
+ if (ENABLE_FEATURE_MDEV_CONF) chown(device_name, uid, gid);
+ }
+ if (command) {
+ int rc;
+ char *s;
+
+ s = xasprintf("MDEV=%s", device_name);
+ putenv(s);
+ rc = system(command);
+ s[4] = 0;
+ putenv(s);
+ free(s);
+ free(command);
+ if (rc == -1) bb_perror_msg_and_die("cannot run %s", command);
+ }
+ if (delete) unlink(device_name);
+}
+
+/* Recursive search of /sys/block or /sys/class. path must be a writeable
+ * buffer of size PATH_MAX containing the directory string to start at. */
+
+static void find_dev(char *path)
+{
+ DIR *dir;
+ size_t len = strlen(path);
+ struct dirent *entry;
+
+ dir = opendir(path);
+ if (dir == NULL)
+ return;
+
+ while ((entry = readdir(dir)) != NULL) {
+ struct stat st;
+
+ /* Skip "." and ".." (also skips hidden files, which is ok) */
+
+ if (entry->d_name[0] == '.')
+ continue;
+
+ // uClibc doesn't fill out entry->d_type reliably. so we use lstat().
+
+ snprintf(path+len, PATH_MAX-len, "/%s", entry->d_name);
+ if (!lstat(path, &st) && S_ISDIR(st.st_mode)) find_dev(path);
+ path[len] = 0;
+
+ /* If there's a dev entry, mknod it */
+
+ if (!strcmp(entry->d_name, "dev")) make_device(path, 0);
+ }
+
+ closedir(dir);
+}
+
+int mdev_main(int argc, char *argv[]);
+int mdev_main(int argc, char *argv[])
+{
+ char *action;
+ char *env_path;
+ RESERVE_CONFIG_BUFFER(temp,PATH_MAX);
+
+ xchdir(DEV_PATH);
+
+ /* Scan */
+
+ if (argc == 2 && !strcmp(argv[1],"-s")) {
+ struct stat st;
+
+ xstat("/", &st);
+ bbg.root_major = major(st.st_dev);
+ bbg.root_minor = minor(st.st_dev);
+ strcpy(temp,"/sys/block");
+ find_dev(temp);
+ strcpy(temp,"/sys/class");
+ find_dev(temp);
+
+ /* Hotplug */
+
+ } else {
+ action = getenv("ACTION");
+ env_path = getenv("DEVPATH");
+ if (!action || !env_path)
+ bb_show_usage();
+
+ sprintf(temp, "/sys%s", env_path);
+ if (!strcmp(action, "add")) make_device(temp,0);
+ else if (!strcmp(action, "remove")) make_device(temp,1);
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP) RELEASE_CONFIG_BUFFER(temp);
+ return 0;
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/minix.h b/i/pc104/initrd/conf/busybox/util-linux/minix.h
new file mode 100644
index 0000000..476f327
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/minix.h
@@ -0,0 +1,76 @@
+/*
+ * This is the original minix inode layout on disk.
+ * Note the 8-bit gid and atime and ctime.
+ */
+struct minix1_inode {
+ uint16_t i_mode;
+ uint16_t i_uid;
+ uint32_t i_size;
+ uint32_t i_time;
+ uint8_t i_gid;
+ uint8_t i_nlinks;
+ uint16_t i_zone[9];
+};
+
+/*
+ * The new minix inode has all the time entries, as well as
+ * long block numbers and a third indirect block (7+1+1+1
+ * instead of 7+1+1). Also, some previously 8-bit values are
+ * now 16-bit. The inode is now 64 bytes instead of 32.
+ */
+struct minix2_inode {
+ uint16_t i_mode;
+ uint16_t i_nlinks;
+ uint16_t i_uid;
+ uint16_t i_gid;
+ uint32_t i_size;
+ uint32_t i_atime;
+ uint32_t i_mtime;
+ uint32_t i_ctime;
+ uint32_t i_zone[10];
+};
+
+/*
+ * minix super-block data on disk
+ */
+struct minix_super_block {
+ uint16_t s_ninodes;
+ uint16_t s_nzones;
+ uint16_t s_imap_blocks;
+ uint16_t s_zmap_blocks;
+ uint16_t s_firstdatazone;
+ uint16_t s_log_zone_size;
+ uint32_t s_max_size;
+ uint16_t s_magic;
+ uint16_t s_state;
+ uint32_t s_zones;
+};
+
+struct minix_dir_entry {
+ uint16_t inode;
+ char name[0];
+};
+
+/* Believe it or not, but mount.h has this one #defined */
+#undef BLOCK_SIZE
+
+enum {
+ BLOCK_SIZE = 1024,
+ BITS_PER_BLOCK = BLOCK_SIZE << 3,
+
+ MINIX_ROOT_INO = 1,
+ MINIX_BAD_INO = 2,
+
+ MINIX1_SUPER_MAGIC = 0x137F, /* original minix fs */
+ MINIX1_SUPER_MAGIC2 = 0x138F, /* minix fs, 30 char names */
+ MINIX2_SUPER_MAGIC = 0x2468, /* minix V2 fs */
+ MINIX2_SUPER_MAGIC2 = 0x2478, /* minix V2 fs, 30 char names */
+ MINIX_VALID_FS = 0x0001, /* clean fs */
+ MINIX_ERROR_FS = 0x0002, /* fs has errors */
+
+ INODE_SIZE1 = sizeof(struct minix1_inode),
+ INODE_SIZE2 = sizeof(struct minix2_inode),
+ MINIX1_INODES_PER_BLOCK = BLOCK_SIZE / sizeof(struct minix1_inode),
+ MINIX2_INODES_PER_BLOCK = BLOCK_SIZE / sizeof(struct minix2_inode),
+};
+
diff --git a/i/pc104/initrd/conf/busybox/util-linux/mkfs_minix.c b/i/pc104/initrd/conf/busybox/util-linux/mkfs_minix.c
new file mode 100644
index 0000000..d70d20f
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/mkfs_minix.c
@@ -0,0 +1,718 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mkfs.c - make a linux (minix) file-system.
+ *
+ * (C) 1991 Linus Torvalds. This file may be redistributed as per
+ * the Linux copyright.
+ */
+
+/*
+ * DD.MM.YY
+ *
+ * 24.11.91 - Time began. Used the fsck sources to get started.
+ *
+ * 25.11.91 - Corrected some bugs. Added support for ".badblocks"
+ * The algorithm for ".badblocks" is a bit weird, but
+ * it should work. Oh, well.
+ *
+ * 25.01.92 - Added the -l option for getting the list of bad blocks
+ * out of a named file. (Dave Rivers, rivers@ponds.uucp)
+ *
+ * 28.02.92 - Added %-information when using -c.
+ *
+ * 28.02.93 - Added support for other namelengths than the original
+ * 14 characters so that I can test the new kernel routines..
+ *
+ * 09.10.93 - Make exit status conform to that required by fsutil
+ * (Rik Faith, faith@cs.unc.edu)
+ *
+ * 31.10.93 - Added inode request feature, for backup floppies: use
+ * 32 inodes, for a news partition use more.
+ * (Scott Heavner, sdh@po.cwru.edu)
+ *
+ * 03.01.94 - Added support for file system valid flag.
+ * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu)
+ *
+ * 30.10.94 - added support for v2 filesystem
+ * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
+ *
+ * 09.11.94 - Added test to prevent overwrite of mounted fs adapted
+ * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs
+ * program. (Daniel Quinlan, quinlan@yggdrasil.com)
+ *
+ * 03.20.95 - Clear first 512 bytes of filesystem to make certain that
+ * the filesystem is not misidentified as a MS-DOS FAT filesystem.
+ * (Daniel Quinlan, quinlan@yggdrasil.com)
+ *
+ * 02.07.96 - Added small patch from Russell King to make the program a
+ * good deal more portable (janl@math.uio.no)
+ *
+ * Usage: mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks]
+ *
+ * -c for readability checking (SLOW!)
+ * -l for getting a list of bad blocks from a file.
+ * -n for namelength (currently the kernel only uses 14 or 30)
+ * -i for number of inodes
+ * -v for v2 filesystem
+ *
+ * The device may be a block device or a image of one, but this isn't
+ * enforced (but it's not much fun on a character device :-).
+ *
+ * Modified for BusyBox by Erik Andersen <andersen@debian.org> --
+ * removed getopt based parser and added a hand rolled one.
+ */
+
+#include "busybox.h"
+#include <mntent.h>
+
+#include "minix.h"
+
+#define DEBUG 0
+
+/* If debugging, store the very same times/uids/gids for image consistency */
+#if DEBUG
+# define CUR_TIME 0
+# define GETUID 0
+# define GETGID 0
+#else
+# define CUR_TIME time(NULL)
+# define GETUID getuid()
+# define GETGID getgid()
+#endif
+
+enum {
+ MAX_GOOD_BLOCKS = 512,
+ TEST_BUFFER_BLOCKS = 16,
+};
+
+#if !ENABLE_FEATURE_MINIX2
+enum { version2 = 0 };
+#endif
+
+struct globals {
+
+ int dev_fd;
+
+#if ENABLE_FEATURE_MINIX2
+ int version2;
+#define version2 G.version2
+#endif
+ char *device_name;
+ uint32_t total_blocks;
+ int badblocks;
+ int namelen;
+ int dirsize;
+ int magic;
+ char *inode_buffer;
+ char *inode_map;
+ char *zone_map;
+ int used_good_blocks;
+ unsigned long req_nr_inodes;
+ unsigned currently_testing;
+
+
+ char root_block[BLOCK_SIZE];
+ char super_block_buffer[BLOCK_SIZE];
+ char boot_block_buffer[512];
+ unsigned short good_blocks_table[MAX_GOOD_BLOCKS];
+ /* check_blocks(): buffer[] was the biggest static in entire bbox */
+ char check_blocks_buffer[BLOCK_SIZE * TEST_BUFFER_BLOCKS];
+};
+
+#define G (*ptr_to_globals)
+
+static ATTRIBUTE_ALWAYS_INLINE unsigned div_roundup(unsigned size, unsigned n)
+{
+ return (size + n-1) / n;
+}
+
+#define INODE_BUF1 (((struct minix1_inode*)G.inode_buffer) - 1)
+#define INODE_BUF2 (((struct minix2_inode*)G.inode_buffer) - 1)
+
+#define SB (*(struct minix_super_block*)G.super_block_buffer)
+
+#define SB_INODES (SB.s_ninodes)
+#define SB_IMAPS (SB.s_imap_blocks)
+#define SB_ZMAPS (SB.s_zmap_blocks)
+#define SB_FIRSTZONE (SB.s_firstdatazone)
+#define SB_ZONE_SIZE (SB.s_log_zone_size)
+#define SB_MAXSIZE (SB.s_max_size)
+#define SB_MAGIC (SB.s_magic)
+
+#if !ENABLE_FEATURE_MINIX2
+# define SB_ZONES (SB.s_nzones)
+# define INODE_BLOCKS div_roundup(SB_INODES, MINIX1_INODES_PER_BLOCK)
+#else
+# define SB_ZONES (version2 ? SB.s_zones : SB.s_nzones)
+# define INODE_BLOCKS div_roundup(SB_INODES, \
+ version2 ? MINIX2_INODES_PER_BLOCK : MINIX1_INODES_PER_BLOCK)
+#endif
+
+#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
+#define NORM_FIRSTZONE (2 + SB_IMAPS + SB_ZMAPS + INODE_BLOCKS)
+
+/* Before you ask "where they come from?": */
+/* setbit/clrbit are supplied by sys/param.h */
+
+static int minix_bit(const char* a, unsigned i)
+{
+ return a[i >> 3] & (1<<(i & 7));
+}
+
+static void minix_setbit(char *a, unsigned i)
+{
+ setbit(a, i);
+}
+static void minix_clrbit(char *a, unsigned i)
+{
+ clrbit(a, i);
+}
+
+/* Note: do not assume 0/1, it is 0/nonzero */
+#define zone_in_use(x) minix_bit(G.zone_map,(x)-SB_FIRSTZONE+1)
+/*#define inode_in_use(x) minix_bit(G.inode_map,(x))*/
+
+#define mark_inode(x) minix_setbit(G.inode_map,(x))
+#define unmark_inode(x) minix_clrbit(G.inode_map,(x))
+#define mark_zone(x) minix_setbit(G.zone_map,(x)-SB_FIRSTZONE+1)
+#define unmark_zone(x) minix_clrbit(G.zone_map,(x)-SB_FIRSTZONE+1)
+
+#ifndef BLKGETSIZE
+# define BLKGETSIZE _IO(0x12,96) /* return device size */
+#endif
+
+
+static long valid_offset(int fd, int offset)
+{
+ char ch;
+
+ if (lseek(fd, offset, SEEK_SET) < 0)
+ return 0;
+ if (read(fd, &ch, 1) < 1)
+ return 0;
+ return 1;
+}
+
+static int count_blocks(int fd)
+{
+ int high, low;
+
+ low = 0;
+ for (high = 1; valid_offset(fd, high); high *= 2)
+ low = high;
+
+ while (low < high - 1) {
+ const int mid = (low + high) / 2;
+
+ if (valid_offset(fd, mid))
+ low = mid;
+ else
+ high = mid;
+ }
+ valid_offset(fd, 0);
+ return (low + 1);
+}
+
+static int get_size(const char *file)
+{
+ int fd;
+ long size;
+
+ fd = xopen(file, O_RDWR);
+ if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
+ close(fd);
+ return (size * 512);
+ }
+
+ size = count_blocks(fd);
+ close(fd);
+ return size;
+}
+
+static void write_tables(void)
+{
+ /* Mark the super block valid. */
+ SB.s_state |= MINIX_VALID_FS;
+ SB.s_state &= ~MINIX_ERROR_FS;
+
+ msg_eol = "seek to 0 failed";
+ xlseek(G.dev_fd, 0, SEEK_SET);
+
+ msg_eol = "cannot clear boot sector";
+ xwrite(G.dev_fd, G.boot_block_buffer, 512);
+
+ msg_eol = "seek to BLOCK_SIZE failed";
+ xlseek(G.dev_fd, BLOCK_SIZE, SEEK_SET);
+
+ msg_eol = "cannot write superblock";
+ xwrite(G.dev_fd, G.super_block_buffer, BLOCK_SIZE);
+
+ msg_eol = "cannot write inode map";
+ xwrite(G.dev_fd, G.inode_map, SB_IMAPS * BLOCK_SIZE);
+
+ msg_eol = "cannot write zone map";
+ xwrite(G.dev_fd, G.zone_map, SB_ZMAPS * BLOCK_SIZE);
+
+ msg_eol = "cannot write inodes";
+ xwrite(G.dev_fd, G.inode_buffer, INODE_BUFFER_SIZE);
+
+ msg_eol = "\n";
+}
+
+static void write_block(int blk, char *buffer)
+{
+ xlseek(G.dev_fd, blk * BLOCK_SIZE, SEEK_SET);
+ xwrite(G.dev_fd, buffer, BLOCK_SIZE);
+}
+
+static int get_free_block(void)
+{
+ int blk;
+
+ if (G.used_good_blocks + 1 >= MAX_GOOD_BLOCKS)
+ bb_error_msg_and_die("too many bad blocks");
+ if (G.used_good_blocks)
+ blk = G.good_blocks_table[G.used_good_blocks - 1] + 1;
+ else
+ blk = SB_FIRSTZONE;
+ while (blk < SB_ZONES && zone_in_use(blk))
+ blk++;
+ if (blk >= SB_ZONES)
+ bb_error_msg_and_die("not enough good blocks");
+ G.good_blocks_table[G.used_good_blocks] = blk;
+ G.used_good_blocks++;
+ return blk;
+}
+
+static void mark_good_blocks(void)
+{
+ int blk;
+
+ for (blk = 0; blk < G.used_good_blocks; blk++)
+ mark_zone(G.good_blocks_table[blk]);
+}
+
+static int next(int zone)
+{
+ if (!zone)
+ zone = SB_FIRSTZONE - 1;
+ while (++zone < SB_ZONES)
+ if (zone_in_use(zone))
+ return zone;
+ return 0;
+}
+
+static void make_bad_inode(void)
+{
+ struct minix1_inode *inode = &INODE_BUF1[MINIX_BAD_INO];
+ int i, j, zone;
+ int ind = 0, dind = 0;
+ unsigned short ind_block[BLOCK_SIZE >> 1];
+ unsigned short dind_block[BLOCK_SIZE >> 1];
+
+#define NEXT_BAD (zone = next(zone))
+
+ if (!G.badblocks)
+ return;
+ mark_inode(MINIX_BAD_INO);
+ inode->i_nlinks = 1;
+ /* BTW, setting this makes all images different */
+ /* it's harder to check for bugs then - diff isn't helpful :(... */
+ inode->i_time = CUR_TIME;
+ inode->i_mode = S_IFREG + 0000;
+ inode->i_size = G.badblocks * BLOCK_SIZE;
+ zone = next(0);
+ for (i = 0; i < 7; i++) {
+ inode->i_zone[i] = zone;
+ if (!NEXT_BAD)
+ goto end_bad;
+ }
+ inode->i_zone[7] = ind = get_free_block();
+ memset(ind_block, 0, BLOCK_SIZE);
+ for (i = 0; i < 512; i++) {
+ ind_block[i] = zone;
+ if (!NEXT_BAD)
+ goto end_bad;
+ }
+ inode->i_zone[8] = dind = get_free_block();
+ memset(dind_block, 0, BLOCK_SIZE);
+ for (i = 0; i < 512; i++) {
+ write_block(ind, (char *) ind_block);
+ dind_block[i] = ind = get_free_block();
+ memset(ind_block, 0, BLOCK_SIZE);
+ for (j = 0; j < 512; j++) {
+ ind_block[j] = zone;
+ if (!NEXT_BAD)
+ goto end_bad;
+ }
+ }
+ bb_error_msg_and_die("too many bad blocks");
+ end_bad:
+ if (ind)
+ write_block(ind, (char *) ind_block);
+ if (dind)
+ write_block(dind, (char *) dind_block);
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void make_bad_inode2(void)
+{
+ struct minix2_inode *inode = &INODE_BUF2[MINIX_BAD_INO];
+ int i, j, zone;
+ int ind = 0, dind = 0;
+ unsigned long ind_block[BLOCK_SIZE >> 2];
+ unsigned long dind_block[BLOCK_SIZE >> 2];
+
+ if (!G.badblocks)
+ return;
+ mark_inode(MINIX_BAD_INO);
+ inode->i_nlinks = 1;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CUR_TIME;
+ inode->i_mode = S_IFREG + 0000;
+ inode->i_size = G.badblocks * BLOCK_SIZE;
+ zone = next(0);
+ for (i = 0; i < 7; i++) {
+ inode->i_zone[i] = zone;
+ if (!NEXT_BAD)
+ goto end_bad;
+ }
+ inode->i_zone[7] = ind = get_free_block();
+ memset(ind_block, 0, BLOCK_SIZE);
+ for (i = 0; i < 256; i++) {
+ ind_block[i] = zone;
+ if (!NEXT_BAD)
+ goto end_bad;
+ }
+ inode->i_zone[8] = dind = get_free_block();
+ memset(dind_block, 0, BLOCK_SIZE);
+ for (i = 0; i < 256; i++) {
+ write_block(ind, (char *) ind_block);
+ dind_block[i] = ind = get_free_block();
+ memset(ind_block, 0, BLOCK_SIZE);
+ for (j = 0; j < 256; j++) {
+ ind_block[j] = zone;
+ if (!NEXT_BAD)
+ goto end_bad;
+ }
+ }
+ /* Could make triple indirect block here */
+ bb_error_msg_and_die("too many bad blocks");
+ end_bad:
+ if (ind)
+ write_block(ind, (char *) ind_block);
+ if (dind)
+ write_block(dind, (char *) dind_block);
+}
+#else
+void make_bad_inode2(void);
+#endif
+
+static void make_root_inode(void)
+{
+ struct minix1_inode *inode = &INODE_BUF1[MINIX_ROOT_INO];
+
+ mark_inode(MINIX_ROOT_INO);
+ inode->i_zone[0] = get_free_block();
+ inode->i_nlinks = 2;
+ inode->i_time = CUR_TIME;
+ if (G.badblocks)
+ inode->i_size = 3 * G.dirsize;
+ else {
+ G.root_block[2 * G.dirsize] = '\0';
+ G.root_block[2 * G.dirsize + 1] = '\0';
+ inode->i_size = 2 * G.dirsize;
+ }
+ inode->i_mode = S_IFDIR + 0755;
+ inode->i_uid = GETUID;
+ if (inode->i_uid)
+ inode->i_gid = GETGID;
+ write_block(inode->i_zone[0], G.root_block);
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void make_root_inode2(void)
+{
+ struct minix2_inode *inode = &INODE_BUF2[MINIX_ROOT_INO];
+
+ mark_inode(MINIX_ROOT_INO);
+ inode->i_zone[0] = get_free_block();
+ inode->i_nlinks = 2;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CUR_TIME;
+ if (G.badblocks)
+ inode->i_size = 3 * G.dirsize;
+ else {
+ G.root_block[2 * G.dirsize] = '\0';
+ G.root_block[2 * G.dirsize + 1] = '\0';
+ inode->i_size = 2 * G.dirsize;
+ }
+ inode->i_mode = S_IFDIR + 0755;
+ inode->i_uid = GETUID;
+ if (inode->i_uid)
+ inode->i_gid = GETGID;
+ write_block(inode->i_zone[0], G.root_block);
+}
+#else
+void make_root_inode2(void);
+#endif
+
+/*
+ * Perform a test of a block; return the number of
+ * blocks readable.
+ */
+static size_t do_check(char *buffer, size_t try, unsigned current_block)
+{
+ ssize_t got;
+
+ /* Seek to the correct loc. */
+ msg_eol = "seek failed during testing of blocks";
+ xlseek(G.dev_fd, current_block * BLOCK_SIZE, SEEK_SET);
+ msg_eol = "\n";
+
+ /* Try the read */
+ got = read(G.dev_fd, buffer, try * BLOCK_SIZE);
+ if (got < 0)
+ got = 0;
+ try = ((size_t)got) / BLOCK_SIZE;
+
+ if (got & (BLOCK_SIZE - 1))
+ fprintf(stderr, "Short read at block %u\n", (unsigned)(current_block + try));
+ return try;
+}
+
+static void alarm_intr(int alnum)
+{
+ if (G.currently_testing >= SB_ZONES)
+ return;
+ signal(SIGALRM, alarm_intr);
+ alarm(5);
+ if (!G.currently_testing)
+ return;
+ printf("%d ...", G.currently_testing);
+ fflush(stdout);
+}
+
+static void check_blocks(void)
+{
+ size_t try, got;
+
+ G.currently_testing = 0;
+ signal(SIGALRM, alarm_intr);
+ alarm(5);
+ while (G.currently_testing < SB_ZONES) {
+ msg_eol = "seek failed in check_blocks";
+ xlseek(G.dev_fd, G.currently_testing * BLOCK_SIZE, SEEK_SET);
+ msg_eol = "\n";
+ try = TEST_BUFFER_BLOCKS;
+ if (G.currently_testing + try > SB_ZONES)
+ try = SB_ZONES - G.currently_testing;
+ got = do_check(G.check_blocks_buffer, try, G.currently_testing);
+ G.currently_testing += got;
+ if (got == try)
+ continue;
+ if (G.currently_testing < SB_FIRSTZONE)
+ bb_error_msg_and_die("bad blocks before data-area: cannot make fs");
+ mark_zone(G.currently_testing);
+ G.badblocks++;
+ G.currently_testing++;
+ }
+ alarm(0);
+ printf("%d bad block(s)\n", G.badblocks);
+}
+
+static void get_list_blocks(char *filename)
+{
+ FILE *listfile;
+ unsigned long blockno;
+
+ listfile = xfopen(filename, "r");
+ while (!feof(listfile)) {
+ fscanf(listfile, "%ld\n", &blockno);
+ mark_zone(blockno);
+ G.badblocks++;
+ }
+ printf("%d bad block(s)\n", G.badblocks);
+}
+
+static void setup_tables(void)
+{
+ unsigned long inodes;
+ unsigned norm_firstzone;
+ unsigned sb_zmaps;
+ unsigned i;
+
+ /* memset(G.super_block_buffer, 0, BLOCK_SIZE); */
+ /* memset(G.boot_block_buffer, 0, 512); */
+ SB_MAGIC = G.magic;
+ SB_ZONE_SIZE = 0;
+ SB_MAXSIZE = version2 ? 0x7fffffff : (7 + 512 + 512 * 512) * 1024;
+ if (version2)
+ SB.s_zones = G.total_blocks;
+ else
+ SB.s_nzones = G.total_blocks;
+
+ /* some magic nrs: 1 inode / 3 blocks */
+ if (G.req_nr_inodes == 0)
+ inodes = G.total_blocks / 3;
+ else
+ inodes = G.req_nr_inodes;
+ /* Round up inode count to fill block size */
+ if (version2)
+ inodes = (inodes + MINIX2_INODES_PER_BLOCK - 1) &
+ ~(MINIX2_INODES_PER_BLOCK - 1);
+ else
+ inodes = (inodes + MINIX1_INODES_PER_BLOCK - 1) &
+ ~(MINIX1_INODES_PER_BLOCK - 1);
+ if (inodes > 65535)
+ inodes = 65535;
+ SB_INODES = inodes;
+ SB_IMAPS = div_roundup(SB_INODES + 1, BITS_PER_BLOCK);
+
+ /* Real bad hack but overwise mkfs.minix can be thrown
+ * in infinite loop...
+ * try:
+ * dd if=/dev/zero of=test.fs count=10 bs=1024
+ * mkfs.minix -i 200 test.fs
+ */
+ /* This code is not insane: NORM_FIRSTZONE is not a constant,
+ * it is calculated from SB_INODES, SB_IMAPS and SB_ZMAPS */
+ i = 999;
+ SB_ZMAPS = 0;
+ do {
+ norm_firstzone = NORM_FIRSTZONE;
+ sb_zmaps = div_roundup(G.total_blocks - norm_firstzone + 1, BITS_PER_BLOCK);
+ if (SB_ZMAPS == sb_zmaps) goto got_it;
+ SB_ZMAPS = sb_zmaps;
+ /* new SB_ZMAPS, need to recalc NORM_FIRSTZONE */
+ } while (--i);
+ bb_error_msg_and_die("incompatible size/inode count, try different -i N");
+ got_it:
+
+ SB_FIRSTZONE = norm_firstzone;
+ G.inode_map = xmalloc(SB_IMAPS * BLOCK_SIZE);
+ G.zone_map = xmalloc(SB_ZMAPS * BLOCK_SIZE);
+ memset(G.inode_map, 0xff, SB_IMAPS * BLOCK_SIZE);
+ memset(G.zone_map, 0xff, SB_ZMAPS * BLOCK_SIZE);
+ for (i = SB_FIRSTZONE; i < SB_ZONES; i++)
+ unmark_zone(i);
+ for (i = MINIX_ROOT_INO; i <= SB_INODES; i++)
+ unmark_inode(i);
+ G.inode_buffer = xzalloc(INODE_BUFFER_SIZE);
+ printf("%ld inodes\n", (long)SB_INODES);
+ printf("%ld blocks\n", (long)SB_ZONES);
+ printf("Firstdatazone=%ld (%ld)\n", (long)SB_FIRSTZONE, (long)norm_firstzone);
+ printf("Zonesize=%d\n", BLOCK_SIZE << SB_ZONE_SIZE);
+ printf("Maxsize=%ld\n", (long)SB_MAXSIZE);
+}
+
+int mkfs_minix_main(int argc, char **argv);
+int mkfs_minix_main(int argc, char **argv)
+{
+ struct mntent *mp;
+ unsigned opt;
+ char *tmp;
+ struct stat statbuf;
+ char *str_i, *str_n;
+ char *listfile = NULL;
+
+ PTR_TO_GLOBALS = xzalloc(sizeof(G));
+/* default (changed to 30, per Linus's suggestion, Sun Nov 21 08:05:07 1993) */
+ G.namelen = 30;
+ G.dirsize = 32;
+ G.magic = MINIX1_SUPER_MAGIC2;
+
+ if (INODE_SIZE1 * MINIX1_INODES_PER_BLOCK != BLOCK_SIZE)
+ bb_error_msg_and_die("bad inode size");
+#if ENABLE_FEATURE_MINIX2
+ if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
+ bb_error_msg_and_die("bad inode size");
+#endif
+
+ opt = getopt32(argc, argv, "ci:l:n:v", &str_i, &listfile, &str_n);
+ argv += optind;
+ //if (opt & 1) -c
+ if (opt & 2) G.req_nr_inodes = xatoul(str_i); // -i
+ //if (opt & 4) -l
+ if (opt & 8) { // -n
+ G.namelen = xatoi_u(str_n);
+ if (G.namelen == 14) G.magic = MINIX1_SUPER_MAGIC;
+ else if (G.namelen == 30) G.magic = MINIX1_SUPER_MAGIC2;
+ else bb_show_usage();
+ G.dirsize = G.namelen + 2;
+ }
+ if (opt & 0x10) { // -v
+#if ENABLE_FEATURE_MINIX2
+ version2 = 1;
+#else
+ bb_error_msg_and_die("not compiled with minix v2 support");
+#endif
+ }
+
+ G.device_name = *argv++;
+ if (!G.device_name)
+ bb_show_usage();
+ if (*argv)
+ G.total_blocks = xatou32(*argv);
+ else
+ G.total_blocks = get_size(G.device_name) / 1024;
+
+ if (G.total_blocks < 10)
+ bb_error_msg_and_die("must have at least 10 blocks");
+
+ if (version2) {
+ G.magic = MINIX2_SUPER_MAGIC2;
+ if (G.namelen == 14)
+ G.magic = MINIX2_SUPER_MAGIC;
+ } else if (G.total_blocks > 65535)
+ G.total_blocks = 65535;
+
+ /* Check if it is mounted */
+ mp = find_mount_point(G.device_name, NULL);
+ if (mp && strcmp(G.device_name, mp->mnt_fsname) == 0)
+ bb_error_msg_and_die("%s is mounted on %s; "
+ "refusing to make a filesystem",
+ G.device_name, mp->mnt_dir);
+
+ G.dev_fd = xopen(G.device_name, O_RDWR);
+ if (fstat(G.dev_fd, &statbuf) < 0)
+ bb_error_msg_and_die("cannot stat %s", G.device_name);
+ if (!S_ISBLK(statbuf.st_mode))
+ opt &= ~1; // clear -c (check)
+
+/* I don't know why someone has special code to prevent mkfs.minix
+ * on IDE devices. Why IDE but not SCSI, etc?... */
+#if 0
+ else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
+ /* what is this? */
+ bb_error_msg_and_die("will not try "
+ "to make filesystem on '%s'", G.device_name);
+#endif
+
+ tmp = G.root_block;
+ *(short *) tmp = 1;
+ strcpy(tmp + 2, ".");
+ tmp += G.dirsize;
+ *(short *) tmp = 1;
+ strcpy(tmp + 2, "..");
+ tmp += G.dirsize;
+ *(short *) tmp = 2;
+ strcpy(tmp + 2, ".badblocks");
+
+ setup_tables();
+
+ if (opt & 1) // -c ?
+ check_blocks();
+ else if (listfile)
+ get_list_blocks(listfile);
+
+ if (version2) {
+ make_root_inode2();
+ make_bad_inode2();
+ } else {
+ make_root_inode();
+ make_bad_inode();
+ }
+
+ mark_good_blocks();
+ write_tables();
+ return 0;
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/mkswap.c b/i/pc104/initrd/conf/busybox/util-linux/mkswap.c
new file mode 100644
index 0000000..ac894d5
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/mkswap.c
@@ -0,0 +1,48 @@
+/* vi: set sw=4 ts=4: */
+/* mkswap.c - format swap device (Linux v1 only)
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+#include "busybox.h"
+
+int mkswap_main(int argc, char *argv[]);
+int mkswap_main(int argc, char *argv[])
+{
+ int fd, pagesize;
+ off_t len;
+ unsigned int hdr[129];
+
+ // No options supported.
+
+ if (argc != 2) bb_show_usage();
+
+ // Figure out how big the device is and announce our intentions.
+
+ fd = xopen(argv[1], O_RDWR);
+ len = fdlength(fd);
+ pagesize = getpagesize();
+ printf("Setting up swapspace version 1, size = %"OFF_FMT"d bytes\n",
+ len - pagesize);
+
+ // Make a header.
+
+ memset(hdr, 0, sizeof(hdr));
+ hdr[0] = 1;
+ hdr[1] = (len / pagesize) - 1;
+
+ // Write the header. Sync to disk because some kernel versions check
+ // signature on disk (not in cache) during swapon.
+
+ xlseek(fd, 1024, SEEK_SET);
+ xwrite(fd, hdr, sizeof(hdr));
+ xlseek(fd, pagesize-10, SEEK_SET);
+ xwrite(fd, "SWAPSPACE2", 10);
+ fsync(fd);
+
+ if (ENABLE_FEATURE_CLEAN_UP) close(fd);
+
+ return 0;
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/more.c b/i/pc104/initrd/conf/busybox/util-linux/more.c
new file mode 100644
index 0000000..2a38ef3
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/more.c
@@ -0,0 +1,173 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini more implementation for busybox
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Latest version blended together by Erik Andersen <andersen@codepoet.org>,
+ * based on the original more implementation by Bruce, and code from the
+ * Debian boot-floppies team.
+ *
+ * Termios corrects by Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Licensed under GPLv2 or later, see file License in this tarball for details.
+ */
+
+#include "busybox.h"
+
+
+#if ENABLE_FEATURE_USE_TERMIOS
+static int cin_fileno;
+#include <termios.h>
+#define setTermSettings(fd, argp) tcsetattr(fd, TCSANOW, argp)
+#define getTermSettings(fd, argp) tcgetattr(fd, argp);
+
+static struct termios initial_settings, new_settings;
+
+static void set_tty_to_initial_mode(void)
+{
+ setTermSettings(cin_fileno, &initial_settings);
+}
+
+static void gotsig(int sig)
+{
+ putchar('\n');
+ exit(EXIT_FAILURE);
+}
+#endif /* FEATURE_USE_TERMIOS */
+
+
+int more_main(int argc, char **argv);
+int more_main(int argc, char **argv)
+{
+ int c, lines, input = 0;
+ int please_display_more_prompt = 0;
+ struct stat st;
+ FILE *file;
+ FILE *cin;
+ int len, page_height;
+ int terminal_width;
+ int terminal_height;
+
+ argv++;
+ /* Another popular pager, most, detects when stdout
+ * is not a tty and turns into cat. This makes sense. */
+ if (!isatty(STDOUT_FILENO))
+ return bb_cat(argv);
+ cin = fopen(CURRENT_TTY, "r");
+ if (!cin)
+ return bb_cat(argv);
+
+#if ENABLE_FEATURE_USE_TERMIOS
+ cin_fileno = fileno(cin);
+ getTermSettings(cin_fileno, &initial_settings);
+ new_settings = initial_settings;
+ new_settings.c_lflag &= ~ICANON;
+ new_settings.c_lflag &= ~ECHO;
+ new_settings.c_cc[VMIN] = 1;
+ new_settings.c_cc[VTIME] = 0;
+ setTermSettings(cin_fileno, &new_settings);
+ atexit(set_tty_to_initial_mode);
+ signal(SIGINT, gotsig);
+ signal(SIGQUIT, gotsig);
+ signal(SIGTERM, gotsig);
+#endif
+ please_display_more_prompt = 2;
+
+ do {
+ file = stdin;
+ if (*argv) {
+ file = fopen_or_warn(*argv, "r");
+ if (!file)
+ continue;
+ }
+ st.st_size = 0;
+ fstat(fileno(file), &st);
+
+ please_display_more_prompt &= ~1;
+ /* never returns w, h <= 1 */
+ get_terminal_width_height(fileno(cin), &terminal_width, &terminal_height);
+ terminal_width -= 1;
+ terminal_height -= 1;
+
+ len = 0;
+ lines = 0;
+ page_height = terminal_height;
+ while ((c = getc(file)) != EOF) {
+
+ if ((please_display_more_prompt & 3) == 3) {
+ len = printf("--More-- ");
+ if (/*file != stdin &&*/ st.st_size > 0) {
+ len += printf("(%d%% of %"OFF_FMT"d bytes)",
+ (int) (ftello(file)*100 / st.st_size),
+ st.st_size);
+ }
+ fflush(stdout);
+
+ /*
+ * We've just displayed the "--More--" prompt, so now we need
+ * to get input from the user.
+ */
+ input = getc(cin);
+#if !ENABLE_FEATURE_USE_TERMIOS
+ printf("\033[A"); /* up cursor */
+#endif
+ /* Erase the "More" message */
+ printf("\r%*s\r", len, "");
+ len = 0;
+ lines = 0;
+ /* Bottom line on page will become top line
+ * after one page forward. Thus -1: */
+ page_height = terminal_height - 1;
+ please_display_more_prompt &= ~1;
+
+ if (input == 'q')
+ goto end;
+ }
+
+ /*
+ * There are two input streams to worry about here:
+ *
+ * c : the character we are reading from the file being "mored"
+ * input : a character received from the keyboard
+ *
+ * If we hit a newline in the _file_ stream, we want to test and
+ * see if any characters have been hit in the _input_ stream. This
+ * allows the user to quit while in the middle of a file.
+ */
+ if (c == '\n') {
+ /* increment by just one line if we are at
+ * the end of this line */
+ if (input == '\n')
+ please_display_more_prompt |= 1;
+ /* Adjust the terminal height for any overlap, so that
+ * no lines get lost off the top. */
+ if (len >= terminal_width) {
+ int quot, rem;
+ quot = len / terminal_width;
+ rem = len - (quot * terminal_width);
+ page_height -= (quot - 1);
+ if (rem)
+ page_height--;
+ }
+ if (++lines >= page_height) {
+ please_display_more_prompt |= 1;
+ }
+ len = 0;
+ }
+ /*
+ * If we just read a newline from the file being 'mored' and any
+ * key other than a return is hit, scroll by one page
+ */
+ putc(c, stdout);
+ /* My small mind cannot fathom tabs, backspaces,
+ * and UTF-8 */
+ len++;
+ }
+ fclose(file);
+ fflush(stdout);
+ } while (*argv && *++argv);
+ end:
+ return 0;
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/mount.c b/i/pc104/initrd/conf/busybox/util-linux/mount.c
new file mode 100644
index 0000000..567514c
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/mount.c
@@ -0,0 +1,1742 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini mount implementation for busybox
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2005-2006 by Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* Design notes: There is no spec for mount. Remind me to write one.
+
+ mount_main() calls singlemount() which calls mount_it_now().
+
+ mount_main() can loop through /etc/fstab for mount -a
+ singlemount() can loop through /etc/filesystems for fstype detection.
+ mount_it_now() does the actual mount.
+*/
+
+#include "busybox.h"
+#include <mntent.h>
+
+/* Needed for nfs support only... */
+#include <syslog.h>
+#include <sys/utsname.h>
+#undef TRUE
+#undef FALSE
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+
+
+#if defined(__dietlibc__)
+/* 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
+ * dietlibc-0.30 does not have implementation of getmntent_r() */
+/* OTOH: why we use getmntent_r instead of getmntent? TODO... */
+struct mntent *getmntent_r(FILE* stream, struct mntent* result, char* buffer, int bufsize)
+{
+ /* *** XXX FIXME WARNING: This hack is NOT thread safe. --Sampo */
+ struct mntent* ment = getmntent(stream);
+ memcpy(result, ment, sizeof(struct mntent));
+ return result;
+}
+#endif
+
+
+// Not real flags, but we want to be able to check for this.
+enum {
+ MOUNT_USERS = (1<<28)*ENABLE_DESKTOP,
+ MOUNT_NOAUTO = (1<<29),
+ MOUNT_SWAP = (1<<30),
+};
+// TODO: more "user" flag compatibility.
+// "user" option (from mount manpage):
+// Only the user that mounted a filesystem can unmount it again.
+// If any user should be able to unmount, then use users instead of user
+// in the fstab line. The owner option is similar to the user option,
+// with the restriction that the user must be the owner of the special file.
+// This may be useful e.g. for /dev/fd if a login script makes
+// the console user owner of this device.
+
+/* Standard mount options (from -o options or --options), with corresponding
+ * flags */
+
+struct {
+ const char *name;
+ long flags;
+} static mount_options[] = {
+ // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
+
+ USE_FEATURE_MOUNT_LOOP(
+ {"loop", 0},
+ )
+
+ USE_FEATURE_MOUNT_FSTAB(
+ {"defaults", 0},
+ /* {"quiet", 0}, - do not filter out, vfat wants to see it */
+ {"noauto", MOUNT_NOAUTO},
+ {"swap", MOUNT_SWAP},
+ USE_DESKTOP({"user", MOUNT_USERS},)
+ USE_DESKTOP({"users", MOUNT_USERS},)
+ )
+
+ USE_FEATURE_MOUNT_FLAGS(
+ // vfs flags
+ {"nosuid", MS_NOSUID},
+ {"suid", ~MS_NOSUID},
+ {"dev", ~MS_NODEV},
+ {"nodev", MS_NODEV},
+ {"exec", ~MS_NOEXEC},
+ {"noexec", MS_NOEXEC},
+ {"sync", MS_SYNCHRONOUS},
+ {"async", ~MS_SYNCHRONOUS},
+ {"atime", ~MS_NOATIME},
+ {"noatime", MS_NOATIME},
+ {"diratime", ~MS_NODIRATIME},
+ {"nodiratime", MS_NODIRATIME},
+ {"loud", ~MS_SILENT},
+
+ // action flags
+
+ {"bind", MS_BIND},
+ {"move", MS_MOVE},
+ {"shared", MS_SHARED},
+ {"slave", MS_SLAVE},
+ {"private", MS_PRIVATE},
+ {"unbindable", MS_UNBINDABLE},
+ {"rshared", MS_SHARED|MS_RECURSIVE},
+ {"rslave", MS_SLAVE|MS_RECURSIVE},
+ {"rprivate", MS_SLAVE|MS_RECURSIVE},
+ {"runbindable", MS_UNBINDABLE|MS_RECURSIVE},
+ )
+
+ // Always understood.
+
+ {"ro", MS_RDONLY}, // vfs flag
+ {"rw", ~MS_RDONLY}, // vfs flag
+ {"remount", MS_REMOUNT}, // action flag
+};
+
+#define VECTOR_SIZE(v) (sizeof(v) / sizeof((v)[0]))
+
+/* Append mount options to string */
+static void append_mount_options(char **oldopts, const char *newopts)
+{
+ if (*oldopts && **oldopts) {
+ /* do not insert options which are already there */
+ while (newopts[0]) {
+ char *p;
+ int len = strlen(newopts);
+ p = strchr(newopts, ',');
+ if (p) len = p - newopts;
+ p = *oldopts;
+ while (1) {
+ if (!strncmp(p, newopts, len)
+ && (p[len]==',' || p[len]==0))
+ goto skip;
+ p = strchr(p,',');
+ if(!p) break;
+ p++;
+ }
+ p = xasprintf("%s,%.*s", *oldopts, len, newopts);
+ free(*oldopts);
+ *oldopts = p;
+skip:
+ newopts += len;
+ while (newopts[0] == ',') newopts++;
+ }
+ } else {
+ if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
+ *oldopts = xstrdup(newopts);
+ }
+}
+
+/* Use the mount_options list to parse options into flags.
+ * Also return list of unrecognized options if unrecognized!=NULL */
+static int parse_mount_options(char *options, char **unrecognized)
+{
+ int flags = MS_SILENT;
+
+ // Loop through options
+ for (;;) {
+ int i;
+ char *comma = strchr(options, ',');
+
+ if (comma) *comma = 0;
+
+ // Find this option in mount_options
+ for (i = 0; i < VECTOR_SIZE(mount_options); i++) {
+ if (!strcasecmp(mount_options[i].name, options)) {
+ long fl = mount_options[i].flags;
+ if (fl < 0) flags &= fl;
+ else flags |= fl;
+ break;
+ }
+ }
+ // If unrecognized not NULL, append unrecognized mount options */
+ if (unrecognized && i == VECTOR_SIZE(mount_options)) {
+ // Add it to strflags, to pass on to kernel
+ i = *unrecognized ? strlen(*unrecognized) : 0;
+ *unrecognized = xrealloc(*unrecognized, i+strlen(options)+2);
+
+ // Comma separated if it's not the first one
+ if (i) (*unrecognized)[i++] = ',';
+ strcpy((*unrecognized)+i, options);
+ }
+
+ // Advance to next option, or finish
+ if (comma) {
+ *comma = ',';
+ options = ++comma;
+ } else break;
+ }
+
+ return flags;
+}
+
+// Return a list of all block device backed filesystems
+
+static llist_t *get_block_backed_filesystems(void)
+{
+ static const char *const filesystems[] = {
+ "/etc/filesystems",
+ "/proc/filesystems",
+ 0
+ };
+ char *fs, *buf;
+ llist_t *list = 0;
+ int i;
+ FILE *f;
+
+ for (i = 0; filesystems[i]; i++) {
+ f = fopen(filesystems[i], "r");
+ if (!f) continue;
+
+ while ((buf = xmalloc_getline(f)) != 0) {
+ if (!strncmp(buf, "nodev", 5) && isspace(buf[5]))
+ continue;
+ fs = skip_whitespace(buf);
+ if (*fs=='#' || *fs=='*' || !*fs) continue;
+
+ llist_add_to_end(&list, xstrdup(fs));
+ free(buf);
+ }
+ if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
+ }
+
+ return list;
+}
+
+llist_t *fslist = 0;
+
+#if ENABLE_FEATURE_CLEAN_UP
+static void delete_block_backed_filesystems(void)
+{
+ llist_free(fslist, free);
+}
+#else
+void delete_block_backed_filesystems(void);
+#endif
+
+#if ENABLE_FEATURE_MTAB_SUPPORT
+static int useMtab = 1;
+static int fakeIt;
+#else
+#define useMtab 0
+#define fakeIt 0
+#endif
+
+// Perform actual mount of specific filesystem at specific location.
+// NB: mp->xxx fields may be trashed on exit
+static int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts)
+{
+ int rc = 0;
+
+ if (fakeIt) goto mtab;
+
+ // Mount, with fallback to read-only if necessary.
+
+ for (;;) {
+ rc = mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
+ vfsflags, filteropts);
+ if (!rc || (vfsflags&MS_RDONLY) || (errno!=EACCES && errno!=EROFS))
+ break;
+ bb_error_msg("%s is write-protected, mounting read-only",
+ mp->mnt_fsname);
+ vfsflags |= MS_RDONLY;
+ }
+
+ // Abort entirely if permission denied.
+
+ if (rc && errno == EPERM)
+ bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+
+ /* If the mount was successful, and we're maintaining an old-style
+ * mtab file by hand, add the new entry to it now. */
+ mtab:
+ if (ENABLE_FEATURE_MTAB_SUPPORT && useMtab && !rc && !(vfsflags & MS_REMOUNT)) {
+ char *fsname;
+ FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
+ int i;
+
+ if (!mountTable) {
+ bb_error_msg("no %s",bb_path_mtab_file);
+ goto ret;
+ }
+
+ // Add vfs string flags
+
+ for (i=0; mount_options[i].flags != MS_REMOUNT; i++)
+ if (mount_options[i].flags > 0 && (mount_options[i].flags & vfsflags))
+ append_mount_options(&(mp->mnt_opts), mount_options[i].name);
+
+ // Remove trailing / (if any) from directory we mounted on
+
+ i = strlen(mp->mnt_dir) - 1;
+ if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = 0;
+
+ // Convert to canonical pathnames as needed
+
+ mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
+ fsname = 0;
+ if (!mp->mnt_type || !*mp->mnt_type) { /* bind mount */
+ mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
+ mp->mnt_type = (char*)"bind";
+ }
+ mp->mnt_freq = mp->mnt_passno = 0;
+
+ // Write and close.
+
+ addmntent(mountTable, mp);
+ endmntent(mountTable);
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(mp->mnt_dir);
+ free(fsname);
+ }
+ }
+ ret:
+ return rc;
+}
+
+#if ENABLE_FEATURE_MOUNT_NFS
+
+/*
+ * Linux NFS mount
+ * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ *
+ * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
+ * numbers to be specified on the command line.
+ *
+ * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
+ * Omit the call to connect() for Linux version 1.3.11 or later.
+ *
+ * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
+ * Implemented the "bg", "fg" and "retry" mount options for NFS.
+ *
+ * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
+ * - added Native Language Support
+ *
+ * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
+ * plus NFSv3 stuff.
+ */
+
+/* This is just a warning of a common mistake. Possibly this should be a
+ * uclibc faq entry rather than in busybox... */
+#if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
+#error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."
+#endif
+
+#define MOUNTPORT 635
+#define MNTPATHLEN 1024
+#define MNTNAMLEN 255
+#define FHSIZE 32
+#define FHSIZE3 64
+
+typedef char fhandle[FHSIZE];
+
+typedef struct {
+ unsigned int fhandle3_len;
+ char *fhandle3_val;
+} fhandle3;
+
+enum mountstat3 {
+ MNT_OK = 0,
+ MNT3ERR_PERM = 1,
+ MNT3ERR_NOENT = 2,
+ MNT3ERR_IO = 5,
+ MNT3ERR_ACCES = 13,
+ MNT3ERR_NOTDIR = 20,
+ MNT3ERR_INVAL = 22,
+ MNT3ERR_NAMETOOLONG = 63,
+ MNT3ERR_NOTSUPP = 10004,
+ MNT3ERR_SERVERFAULT = 10006,
+};
+typedef enum mountstat3 mountstat3;
+
+struct fhstatus {
+ unsigned int fhs_status;
+ union {
+ fhandle fhs_fhandle;
+ } fhstatus_u;
+};
+typedef struct fhstatus fhstatus;
+
+struct mountres3_ok {
+ fhandle3 fhandle;
+ struct {
+ unsigned int auth_flavours_len;
+ char *auth_flavours_val;
+ } auth_flavours;
+};
+typedef struct mountres3_ok mountres3_ok;
+
+struct mountres3 {
+ mountstat3 fhs_status;
+ union {
+ mountres3_ok mountinfo;
+ } mountres3_u;
+};
+typedef struct mountres3 mountres3;
+
+typedef char *dirpath;
+
+typedef char *name;
+
+typedef struct mountbody *mountlist;
+
+struct mountbody {
+ name ml_hostname;
+ dirpath ml_directory;
+ mountlist ml_next;
+};
+typedef struct mountbody mountbody;
+
+typedef struct groupnode *groups;
+
+struct groupnode {
+ name gr_name;
+ groups gr_next;
+};
+typedef struct groupnode groupnode;
+
+typedef struct exportnode *exports;
+
+struct exportnode {
+ dirpath ex_dir;
+ groups ex_groups;
+ exports ex_next;
+};
+typedef struct exportnode exportnode;
+
+struct ppathcnf {
+ int pc_link_max;
+ short pc_max_canon;
+ short pc_max_input;
+ short pc_name_max;
+ short pc_path_max;
+ short pc_pipe_buf;
+ uint8_t pc_vdisable;
+ char pc_xxx;
+ short pc_mask[2];
+};
+typedef struct ppathcnf ppathcnf;
+
+#define MOUNTPROG 100005
+#define MOUNTVERS 1
+
+#define MOUNTPROC_NULL 0
+#define MOUNTPROC_MNT 1
+#define MOUNTPROC_DUMP 2
+#define MOUNTPROC_UMNT 3
+#define MOUNTPROC_UMNTALL 4
+#define MOUNTPROC_EXPORT 5
+#define MOUNTPROC_EXPORTALL 6
+
+#define MOUNTVERS_POSIX 2
+
+#define MOUNTPROC_PATHCONF 7
+
+#define MOUNT_V3 3
+
+#define MOUNTPROC3_NULL 0
+#define MOUNTPROC3_MNT 1
+#define MOUNTPROC3_DUMP 2
+#define MOUNTPROC3_UMNT 3
+#define MOUNTPROC3_UMNTALL 4
+#define MOUNTPROC3_EXPORT 5
+
+enum {
+#ifndef NFS_FHSIZE
+ NFS_FHSIZE = 32,
+#endif
+#ifndef NFS_PORT
+ NFS_PORT = 2049
+#endif
+};
+
+/*
+ * We want to be able to compile mount on old kernels in such a way
+ * that the binary will work well on more recent kernels.
+ * Thus, if necessary we teach nfsmount.c the structure of new fields
+ * that will come later.
+ *
+ * Moreover, the new kernel includes conflict with glibc includes
+ * so it is easiest to ignore the kernel altogether (at compile time).
+ */
+
+struct nfs2_fh {
+ char data[32];
+};
+struct nfs3_fh {
+ unsigned short size;
+ unsigned char data[64];
+};
+
+struct nfs_mount_data {
+ int version; /* 1 */
+ int fd; /* 1 */
+ struct nfs2_fh old_root; /* 1 */
+ int flags; /* 1 */
+ int rsize; /* 1 */
+ int wsize; /* 1 */
+ int timeo; /* 1 */
+ int retrans; /* 1 */
+ int acregmin; /* 1 */
+ int acregmax; /* 1 */
+ int acdirmin; /* 1 */
+ int acdirmax; /* 1 */
+ struct sockaddr_in addr; /* 1 */
+ char hostname[256]; /* 1 */
+ int namlen; /* 2 */
+ unsigned int bsize; /* 3 */
+ struct nfs3_fh root; /* 4 */
+};
+
+/* bits in the flags field */
+enum {
+ NFS_MOUNT_SOFT = 0x0001, /* 1 */
+ NFS_MOUNT_INTR = 0x0002, /* 1 */
+ NFS_MOUNT_SECURE = 0x0004, /* 1 */
+ NFS_MOUNT_POSIX = 0x0008, /* 1 */
+ NFS_MOUNT_NOCTO = 0x0010, /* 1 */
+ NFS_MOUNT_NOAC = 0x0020, /* 1 */
+ NFS_MOUNT_TCP = 0x0040, /* 2 */
+ NFS_MOUNT_VER3 = 0x0080, /* 3 */
+ NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
+ NFS_MOUNT_NONLM = 0x0200 /* 3 */
+};
+
+
+/*
+ * We need to translate between nfs status return values and
+ * the local errno values which may not be the same.
+ *
+ * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
+ * "after #include <errno.h> the symbol errno is reserved for any use,
+ * it cannot even be used as a struct tag or field name".
+ */
+
+#ifndef EDQUOT
+#define EDQUOT ENOSPC
+#endif
+
+// Convert each NFSERR_BLAH into EBLAH
+
+static const struct {
+ int stat;
+ int errnum;
+} nfs_errtbl[] = {
+ {0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST},
+ {19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG},
+ {28,ENOSPC}, {30,EROFS}, {63,ENAMETOOLONG}, {66,ENOTEMPTY}, {69,EDQUOT},
+ {70,ESTALE}, {71,EREMOTE}, {-1,EIO}
+};
+
+static char *nfs_strerror(int status)
+{
+ int i;
+ static char buf[sizeof("unknown nfs status return value: ") + sizeof(int)*3];
+
+ for (i = 0; nfs_errtbl[i].stat != -1; i++) {
+ if (nfs_errtbl[i].stat == status)
+ return strerror(nfs_errtbl[i].errnum);
+ }
+ sprintf(buf, "unknown nfs status return value: %d", status);
+ return buf;
+}
+
+static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
+{
+ if (!xdr_opaque(xdrs, objp, FHSIZE))
+ return FALSE;
+ return TRUE;
+}
+
+static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
+{
+ if (!xdr_u_int(xdrs, &objp->fhs_status))
+ return FALSE;
+ switch (objp->fhs_status) {
+ case 0:
+ if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
+{
+ if (!xdr_string(xdrs, objp, MNTPATHLEN))
+ return FALSE;
+ return TRUE;
+}
+
+static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
+{
+ if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
+ return FALSE;
+ return TRUE;
+}
+
+static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
+{
+ if (!xdr_fhandle3(xdrs, &objp->fhandle))
+ return FALSE;
+ if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), &(objp->auth_flavours.auth_flavours_len), ~0,
+ sizeof (int), (xdrproc_t) xdr_int))
+ return FALSE;
+ return TRUE;
+}
+
+static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *) objp))
+ return FALSE;
+ return TRUE;
+}
+
+static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
+{
+ if (!xdr_mountstat3(xdrs, &objp->fhs_status))
+ return FALSE;
+ switch (objp->fhs_status) {
+ case MNT_OK:
+ if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
+
+/*
+ * nfs_mount_version according to the sources seen at compile time.
+ */
+static int nfs_mount_version;
+static int kernel_version;
+
+/*
+ * Unfortunately, the kernel prints annoying console messages
+ * in case of an unexpected nfs mount version (instead of
+ * just returning some error). Therefore we'll have to try
+ * and figure out what version the kernel expects.
+ *
+ * Variables:
+ * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
+ * NFS_MOUNT_VERSION: these nfsmount sources at compile time
+ * nfs_mount_version: version this source and running kernel can handle
+ */
+static void
+find_kernel_nfs_mount_version(void)
+{
+ if (kernel_version)
+ return;
+
+ nfs_mount_version = 4; /* default */
+
+ kernel_version = get_linux_version_code();
+ if (kernel_version) {
+ if (kernel_version < KERNEL_VERSION(2,1,32))
+ nfs_mount_version = 1;
+ else if (kernel_version < KERNEL_VERSION(2,2,18) ||
+ (kernel_version >= KERNEL_VERSION(2,3,0) &&
+ kernel_version < KERNEL_VERSION(2,3,99)))
+ nfs_mount_version = 3;
+ /* else v4 since 2.3.99pre4 */
+ }
+}
+
+static struct pmap *
+get_mountport(struct sockaddr_in *server_addr,
+ long unsigned prog,
+ long unsigned version,
+ long unsigned proto,
+ long unsigned port)
+{
+ struct pmaplist *pmap;
+ static struct pmap p = {0, 0, 0, 0};
+
+ server_addr->sin_port = PMAPPORT;
+/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
+ * I understand it like "IPv6 for this is not 100% ready" */
+ pmap = pmap_getmaps(server_addr);
+
+ if (version > MAX_NFSPROT)
+ version = MAX_NFSPROT;
+ if (!prog)
+ prog = MOUNTPROG;
+ p.pm_prog = prog;
+ p.pm_vers = version;
+ p.pm_prot = proto;
+ p.pm_port = port;
+
+ while (pmap) {
+ if (pmap->pml_map.pm_prog != prog)
+ goto next;
+ if (!version && p.pm_vers > pmap->pml_map.pm_vers)
+ goto next;
+ if (version > 2 && pmap->pml_map.pm_vers != version)
+ goto next;
+ if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
+ goto next;
+ if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
+ (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
+ (port && pmap->pml_map.pm_port != port))
+ goto next;
+ memcpy(&p, &pmap->pml_map, sizeof(p));
+next:
+ pmap = pmap->pml_next;
+ }
+ if (!p.pm_vers)
+ p.pm_vers = MOUNTVERS;
+ if (!p.pm_port)
+ p.pm_port = MOUNTPORT;
+ if (!p.pm_prot)
+ p.pm_prot = IPPROTO_TCP;
+ return &p;
+}
+
+static int daemonize(void)
+{
+ int fd;
+ int pid = fork();
+ if (pid < 0) /* error */
+ return -errno;
+ if (pid > 0) /* parent */
+ return 0;
+ /* child */
+ fd = xopen(bb_dev_null, O_RDWR);
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ while (fd > 2) close(fd--);
+ setsid();
+ openlog(applet_name, LOG_PID, LOG_DAEMON);
+ logmode = LOGMODE_SYSLOG;
+ return 1;
+}
+
+// TODO
+static inline int we_saw_this_host_before(const char *hostname)
+{
+ return 0;
+}
+
+/* RPC strerror analogs are terminally idiotic:
+ * *mandatory* prefix and \n at end.
+ * This hopefully helps. Usage:
+ * error_msg_rpc(clnt_*error*(" ")) */
+static void error_msg_rpc(const char *msg)
+{
+ int len;
+ while (msg[0] == ' ' || msg[0] == ':') msg++;
+ len = strlen(msg);
+ while (len && msg[len-1] == '\n') len--;
+ bb_error_msg("%.*s", len, msg);
+}
+
+// NB: mp->xxx fields may be trashed on exit
+static int nfsmount(struct mntent *mp, int vfsflags, char *filteropts)
+{
+ CLIENT *mclient;
+ char *hostname;
+ char *pathname;
+ char *mounthost;
+ struct nfs_mount_data data;
+ char *opt;
+ struct hostent *hp;
+ struct sockaddr_in server_addr;
+ struct sockaddr_in mount_server_addr;
+ int msock, fsock;
+ union {
+ struct fhstatus nfsv2;
+ struct mountres3 nfsv3;
+ } status;
+ int daemonized;
+ char *s;
+ int port;
+ int mountport;
+ int proto;
+ int bg;
+ int soft;
+ int intr;
+ int posix;
+ int nocto;
+ int noac;
+ int nolock;
+ int retry;
+ int tcp;
+ int mountprog;
+ int mountvers;
+ int nfsprog;
+ int nfsvers;
+ int retval;
+
+ find_kernel_nfs_mount_version();
+
+ daemonized = 0;
+ mounthost = NULL;
+ retval = ETIMEDOUT;
+ msock = fsock = -1;
+ mclient = NULL;
+
+ /* NB: hostname, mounthost, filteropts must be free()d prior to return */
+
+ filteropts = xstrdup(filteropts); /* going to trash it later... */
+
+ hostname = xstrdup(mp->mnt_fsname);
+ /* mount_main() guarantees that ':' is there */
+ s = strchr(hostname, ':');
+ pathname = s + 1;
+ *s = '\0';
+ /* Ignore all but first hostname in replicated mounts
+ until they can be fully supported. (mack@sgi.com) */
+ s = strchr(hostname, ',');
+ if (s) {
+ *s = '\0';
+ bb_error_msg("warning: multiple hostnames not supported");
+ }
+
+ server_addr.sin_family = AF_INET;
+ if (!inet_aton(hostname, &server_addr.sin_addr)) {
+ hp = gethostbyname(hostname);
+ if (hp == NULL) {
+ bb_herror_msg("%s", hostname);
+ goto fail;
+ }
+ if (hp->h_length > sizeof(struct in_addr)) {
+ bb_error_msg("got bad hp->h_length");
+ hp->h_length = sizeof(struct in_addr);
+ }
+ memcpy(&server_addr.sin_addr,
+ hp->h_addr, hp->h_length);
+ }
+
+ memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
+
+ /* add IP address to mtab options for use when unmounting */
+
+ if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
+ mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
+ } else {
+ char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
+ mp->mnt_opts[0] ? "," : "",
+ inet_ntoa(server_addr.sin_addr));
+ free(mp->mnt_opts);
+ mp->mnt_opts = tmp;
+ }
+
+ /* Set default options.
+ * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
+ * let the kernel decide.
+ * timeo is filled in after we know whether it'll be TCP or UDP. */
+ memset(&data, 0, sizeof(data));
+ data.retrans = 3;
+ data.acregmin = 3;
+ data.acregmax = 60;
+ data.acdirmin = 30;
+ data.acdirmax = 60;
+ data.namlen = NAME_MAX;
+
+ bg = 0;
+ soft = 0;
+ intr = 0;
+ posix = 0;
+ nocto = 0;
+ nolock = 0;
+ noac = 0;
+ retry = 10000; /* 10000 minutes ~ 1 week */
+ tcp = 0;
+
+ mountprog = MOUNTPROG;
+ mountvers = 0;
+ port = 0;
+ mountport = 0;
+ nfsprog = 100003;
+ nfsvers = 0;
+
+ /* parse options */
+
+ for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
+ char *opteq = strchr(opt, '=');
+ if (opteq) {
+ const char *const options[] = {
+ /* 0 */ "rsize",
+ /* 1 */ "wsize",
+ /* 2 */ "timeo",
+ /* 3 */ "retrans",
+ /* 4 */ "acregmin",
+ /* 5 */ "acregmax",
+ /* 6 */ "acdirmin",
+ /* 7 */ "acdirmax",
+ /* 8 */ "actimeo",
+ /* 9 */ "retry",
+ /* 10 */ "port",
+ /* 11 */ "mountport",
+ /* 12 */ "mounthost",
+ /* 13 */ "mountprog",
+ /* 14 */ "mountvers",
+ /* 15 */ "nfsprog",
+ /* 16 */ "nfsvers",
+ /* 17 */ "vers",
+ /* 18 */ "proto",
+ /* 19 */ "namlen",
+ /* 20 */ "addr",
+ NULL
+ };
+ int val = xatoi_u(opteq + 1);
+ *opteq = '\0';
+ switch (index_in_str_array(options, opt)) {
+ case 0: // "rsize"
+ data.rsize = val;
+ break;
+ case 1: // "wsize"
+ data.wsize = val;
+ break;
+ case 2: // "timeo"
+ data.timeo = val;
+ break;
+ case 3: // "retrans"
+ data.retrans = val;
+ break;
+ case 4: // "acregmin"
+ data.acregmin = val;
+ break;
+ case 5: // "acregmax"
+ data.acregmax = val;
+ break;
+ case 6: // "acdirmin"
+ data.acdirmin = val;
+ break;
+ case 7: // "acdirmax"
+ data.acdirmax = val;
+ break;
+ case 8: // "actimeo"
+ data.acregmin = val;
+ data.acregmax = val;
+ data.acdirmin = val;
+ data.acdirmax = val;
+ break;
+ case 9: // "retry"
+ retry = val;
+ break;
+ case 10: // "port"
+ port = val;
+ break;
+ case 11: // "mountport"
+ mountport = val;
+ break;
+ case 12: // "mounthost"
+ mounthost = xstrndup(opteq+1,
+ strcspn(opteq+1," \t\n\r,"));
+ break;
+ case 13: // "mountprog"
+ mountprog = val;
+ break;
+ case 14: // "mountvers"
+ mountvers = val;
+ break;
+ case 15: // "nfsprog"
+ nfsprog = val;
+ break;
+ case 16: // "nfsvers"
+ case 17: // "vers"
+ nfsvers = val;
+ break;
+ case 18: // "proto"
+ if (!strncmp(opteq+1, "tcp", 3))
+ tcp = 1;
+ else if (!strncmp(opteq+1, "udp", 3))
+ tcp = 0;
+ else
+ bb_error_msg("warning: unrecognized proto= option");
+ break;
+ case 19: // "namlen"
+ if (nfs_mount_version >= 2)
+ data.namlen = val;
+ else
+ bb_error_msg("warning: option namlen is not supported\n");
+ break;
+ case 20: // "addr" - ignore
+ break;
+ default:
+ bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
+ goto fail;
+ }
+ }
+ else {
+ const char *const options[] = {
+ "bg",
+ "fg",
+ "soft",
+ "hard",
+ "intr",
+ "posix",
+ "cto",
+ "ac",
+ "tcp",
+ "udp",
+ "lock",
+ NULL
+ };
+ int val = 1;
+ if (!strncmp(opt, "no", 2)) {
+ val = 0;
+ opt += 2;
+ }
+ switch (index_in_str_array(options, opt)) {
+ case 0: // "bg"
+ bg = val;
+ break;
+ case 1: // "fg"
+ bg = !val;
+ break;
+ case 2: // "soft"
+ soft = val;
+ break;
+ case 3: // "hard"
+ soft = !val;
+ break;
+ case 4: // "intr"
+ intr = val;
+ break;
+ case 5: // "posix"
+ posix = val;
+ break;
+ case 6: // "cto"
+ nocto = !val;
+ break;
+ case 7: // "ac"
+ noac = !val;
+ break;
+ case 8: // "tcp"
+ tcp = val;
+ break;
+ case 9: // "udp"
+ tcp = !val;
+ break;
+ case 10: // "lock"
+ if (nfs_mount_version >= 3)
+ nolock = !val;
+ else
+ bb_error_msg("warning: option nolock is not supported");
+ break;
+ default:
+ bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
+ goto fail;
+ }
+ }
+ }
+ proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
+
+ data.flags = (soft ? NFS_MOUNT_SOFT : 0)
+ | (intr ? NFS_MOUNT_INTR : 0)
+ | (posix ? NFS_MOUNT_POSIX : 0)
+ | (nocto ? NFS_MOUNT_NOCTO : 0)
+ | (noac ? NFS_MOUNT_NOAC : 0);
+ if (nfs_mount_version >= 2)
+ data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
+ if (nfs_mount_version >= 3)
+ data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
+ if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
+ bb_error_msg("NFSv%d not supported", nfsvers);
+ goto fail;
+ }
+ if (nfsvers && !mountvers)
+ mountvers = (nfsvers < 3) ? 1 : nfsvers;
+ if (nfsvers && nfsvers < mountvers) {
+ mountvers = nfsvers;
+ }
+
+ /* Adjust options if none specified */
+ if (!data.timeo)
+ data.timeo = tcp ? 70 : 7;
+
+ data.version = nfs_mount_version;
+
+ if (vfsflags & MS_REMOUNT)
+ goto do_mount;
+
+ /*
+ * If the previous mount operation on the same host was
+ * backgrounded, and the "bg" for this mount is also set,
+ * give up immediately, to avoid the initial timeout.
+ */
+ if (bg && we_saw_this_host_before(hostname)) {
+ daemonized = daemonize(); /* parent or error */
+ if (daemonized <= 0) { /* parent or error */
+ retval = -daemonized;
+ goto ret;
+ }
+ }
+
+ /* create mount daemon client */
+ /* See if the nfs host = mount host. */
+ if (mounthost) {
+ if (mounthost[0] >= '0' && mounthost[0] <= '9') {
+ mount_server_addr.sin_family = AF_INET;
+ mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
+ } else {
+ hp = gethostbyname(mounthost);
+ if (hp == NULL) {
+ bb_herror_msg("%s", mounthost);
+ goto fail;
+ } else {
+ if (hp->h_length > sizeof(struct in_addr)) {
+ bb_error_msg("got bad hp->h_length?");
+ hp->h_length = sizeof(struct in_addr);
+ }
+ mount_server_addr.sin_family = AF_INET;
+ memcpy(&mount_server_addr.sin_addr,
+ hp->h_addr, hp->h_length);
+ }
+ }
+ }
+
+ /*
+ * The following loop implements the mount retries. When the mount
+ * times out, and the "bg" option is set, we background ourself
+ * and continue trying.
+ *
+ * The case where the mount point is not present and the "bg"
+ * option is set, is treated as a timeout. This is done to
+ * support nested mounts.
+ *
+ * The "retry" count specified by the user is the number of
+ * minutes to retry before giving up.
+ */
+ {
+ struct timeval total_timeout;
+ struct timeval retry_timeout;
+ struct pmap* pm_mnt;
+ time_t t;
+ time_t prevt;
+ time_t timeout;
+
+ retry_timeout.tv_sec = 3;
+ retry_timeout.tv_usec = 0;
+ total_timeout.tv_sec = 20;
+ total_timeout.tv_usec = 0;
+ timeout = time(NULL) + 60 * retry;
+ prevt = 0;
+ t = 30;
+retry:
+ /* be careful not to use too many CPU cycles */
+ if (t - prevt < 30)
+ sleep(30);
+
+ pm_mnt = get_mountport(&mount_server_addr,
+ mountprog,
+ mountvers,
+ proto,
+ mountport);
+ nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
+
+ /* contact the mount daemon via TCP */
+ mount_server_addr.sin_port = htons(pm_mnt->pm_port);
+ msock = RPC_ANYSOCK;
+
+ switch (pm_mnt->pm_prot) {
+ case IPPROTO_UDP:
+ mclient = clntudp_create(&mount_server_addr,
+ pm_mnt->pm_prog,
+ pm_mnt->pm_vers,
+ retry_timeout,
+ &msock);
+ if (mclient)
+ break;
+ mount_server_addr.sin_port = htons(pm_mnt->pm_port);
+ msock = RPC_ANYSOCK;
+ case IPPROTO_TCP:
+ mclient = clnttcp_create(&mount_server_addr,
+ pm_mnt->pm_prog,
+ pm_mnt->pm_vers,
+ &msock, 0, 0);
+ break;
+ default:
+ mclient = 0;
+ }
+ if (!mclient) {
+ if (!daemonized && prevt == 0)
+ error_msg_rpc(clnt_spcreateerror(" "));
+ } else {
+ enum clnt_stat clnt_stat;
+ /* try to mount hostname:pathname */
+ mclient->cl_auth = authunix_create_default();
+
+ /* make pointers in xdr_mountres3 NULL so
+ * that xdr_array allocates memory for us
+ */
+ memset(&status, 0, sizeof(status));
+
+ if (pm_mnt->pm_vers == 3)
+ clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
+ (xdrproc_t) xdr_dirpath,
+ (caddr_t) &pathname,
+ (xdrproc_t) xdr_mountres3,
+ (caddr_t) &status,
+ total_timeout);
+ else
+ clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
+ (xdrproc_t) xdr_dirpath,
+ (caddr_t) &pathname,
+ (xdrproc_t) xdr_fhstatus,
+ (caddr_t) &status,
+ total_timeout);
+
+ if (clnt_stat == RPC_SUCCESS)
+ goto prepare_kernel_data; /* we're done */
+ if (errno != ECONNREFUSED) {
+ error_msg_rpc(clnt_sperror(mclient, " "));
+ goto fail; /* don't retry */
+ }
+ /* Connection refused */
+ if (!daemonized && prevt == 0) /* print just once */
+ error_msg_rpc(clnt_sperror(mclient, " "));
+ auth_destroy(mclient->cl_auth);
+ clnt_destroy(mclient);
+ mclient = 0;
+ close(msock);
+ }
+
+ /* Timeout. We are going to retry... maybe */
+
+ if (!bg)
+ goto fail;
+ if (!daemonized) {
+ daemonized = daemonize();
+ if (daemonized <= 0) { /* parent or error */
+ retval = -daemonized;
+ goto ret;
+ }
+ }
+ prevt = t;
+ t = time(NULL);
+ if (t >= timeout)
+ /* TODO error message */
+ goto fail;
+
+ goto retry;
+ }
+
+prepare_kernel_data:
+
+ if (nfsvers == 2) {
+ if (status.nfsv2.fhs_status != 0) {
+ bb_error_msg("%s:%s failed, reason given by server: %s",
+ hostname, pathname,
+ nfs_strerror(status.nfsv2.fhs_status));
+ goto fail;
+ }
+ memcpy(data.root.data,
+ (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
+ NFS_FHSIZE);
+ data.root.size = NFS_FHSIZE;
+ memcpy(data.old_root.data,
+ (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
+ NFS_FHSIZE);
+ } else {
+ fhandle3 *my_fhandle;
+ if (status.nfsv3.fhs_status != 0) {
+ bb_error_msg("%s:%s failed, reason given by server: %s",
+ hostname, pathname,
+ nfs_strerror(status.nfsv3.fhs_status));
+ goto fail;
+ }
+ my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
+ memset(data.old_root.data, 0, NFS_FHSIZE);
+ memset(&data.root, 0, sizeof(data.root));
+ data.root.size = my_fhandle->fhandle3_len;
+ memcpy(data.root.data,
+ (char *) my_fhandle->fhandle3_val,
+ my_fhandle->fhandle3_len);
+
+ data.flags |= NFS_MOUNT_VER3;
+ }
+
+ /* create nfs socket for kernel */
+
+ if (tcp) {
+ if (nfs_mount_version < 3) {
+ bb_error_msg("NFS over TCP is not supported");
+ goto fail;
+ }
+ fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ } else
+ fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (fsock < 0) {
+ bb_perror_msg("nfs socket");
+ goto fail;
+ }
+ if (bindresvport(fsock, 0) < 0) {
+ bb_perror_msg("nfs bindresvport");
+ goto fail;
+ }
+ if (port == 0) {
+ server_addr.sin_port = PMAPPORT;
+ port = pmap_getport(&server_addr, nfsprog, nfsvers,
+ tcp ? IPPROTO_TCP : IPPROTO_UDP);
+ if (port == 0)
+ port = NFS_PORT;
+ }
+ server_addr.sin_port = htons(port);
+
+ /* prepare data structure for kernel */
+
+ data.fd = fsock;
+ memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
+ strncpy(data.hostname, hostname, sizeof(data.hostname));
+
+ /* clean up */
+
+ auth_destroy(mclient->cl_auth);
+ clnt_destroy(mclient);
+ close(msock);
+
+ if (bg) {
+ /* We must wait until mount directory is available */
+ struct stat statbuf;
+ int delay = 1;
+ while (stat(mp->mnt_dir, &statbuf) == -1) {
+ if (!daemonized) {
+ daemonized = daemonize();
+ if (daemonized <= 0) { /* parent or error */
+ retval = -daemonized;
+ goto ret;
+ }
+ }
+ sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
+ delay *= 2;
+ if (delay > 30)
+ delay = 30;
+ }
+ }
+
+do_mount: /* perform actual mount */
+
+ mp->mnt_type = (char*)"nfs";
+ retval = mount_it_now(mp, vfsflags, (char*)&data);
+ goto ret;
+
+fail: /* abort */
+
+ if (msock != -1) {
+ if (mclient) {
+ auth_destroy(mclient->cl_auth);
+ clnt_destroy(mclient);
+ }
+ close(msock);
+ }
+ if (fsock != -1)
+ close(fsock);
+
+ret:
+ free(hostname);
+ free(mounthost);
+ free(filteropts);
+ return retval;
+}
+
+#else /* !ENABLE_FEATURE_MOUNT_NFS */
+
+/* Never called. Call should be optimized out. */
+int nfsmount(struct mntent *mp, int vfsflags, char *filteropts);
+
+#endif /* !ENABLE_FEATURE_MOUNT_NFS */
+
+// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
+// type detection. Returns 0 for success, nonzero for failure.
+// NB: mp->xxx fields may be trashed on exit
+static int singlemount(struct mntent *mp, int ignore_busy)
+{
+ int rc = -1, vfsflags;
+ char *loopFile = 0, *filteropts = 0;
+ llist_t *fl = 0;
+ struct stat st;
+
+ vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
+
+ // Treat fstype "auto" as unspecified.
+
+ if (mp->mnt_type && strcmp(mp->mnt_type,"auto") == 0)
+ mp->mnt_type = 0;
+
+ // Might this be an CIFS filesystem?
+
+ if (ENABLE_FEATURE_MOUNT_CIFS
+ && (!mp->mnt_type || strcmp(mp->mnt_type,"cifs") == 0)
+ && (mp->mnt_fsname[0]=='/' || mp->mnt_fsname[0]=='\\')
+ && mp->mnt_fsname[0]==mp->mnt_fsname[1]
+ ) {
+ len_and_sockaddr *lsa;
+ char *ip, *dotted;
+ char *s;
+
+ rc = 1;
+ // Replace '/' with '\' and verify that unc points to "//server/share".
+
+ for (s = mp->mnt_fsname; *s; ++s)
+ if (*s == '/') *s = '\\';
+
+ // get server IP
+
+ s = strrchr(mp->mnt_fsname, '\\');
+ if (s <= mp->mnt_fsname+1) goto report_error;
+ *s = '\0';
+ lsa = host2sockaddr(mp->mnt_fsname+2, 0);
+ *s = '\\';
+ if (!lsa) goto report_error;
+
+ // insert ip=... option into string flags.
+
+ dotted = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len);
+ ip = xasprintf("ip=%s", dotted);
+ parse_mount_options(ip, &filteropts);
+
+ // compose new unc '\\server-ip\share'
+ // (s => slash after hostname)
+
+ mp->mnt_fsname = xasprintf("\\\\%s%s", dotted, s);
+
+ // lock is required
+ vfsflags |= MS_MANDLOCK;
+
+ mp->mnt_type = (char*)"cifs";
+ rc = mount_it_now(mp, vfsflags, filteropts);
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(mp->mnt_fsname);
+ free(ip);
+ free(dotted);
+ free(lsa);
+ }
+ goto report_error;
+ }
+
+ // Might this be an NFS filesystem?
+
+ if (ENABLE_FEATURE_MOUNT_NFS
+ && (!mp->mnt_type || !strcmp(mp->mnt_type,"nfs"))
+ && strchr(mp->mnt_fsname, ':') != NULL
+ ) {
+ rc = nfsmount(mp, vfsflags, filteropts);
+ goto report_error;
+ }
+
+ // Look at the file. (Not found isn't a failure for remount, or for
+ // a synthetic filesystem like proc or sysfs.)
+
+ if (!lstat(mp->mnt_fsname, &st)
+ && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
+ ) {
+ // Do we need to allocate a loopback device for it?
+
+ if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
+ loopFile = bb_simplify_path(mp->mnt_fsname);
+ mp->mnt_fsname = 0;
+ switch (set_loop(&(mp->mnt_fsname), loopFile, 0)) {
+ case 0:
+ case 1:
+ break;
+ default:
+ bb_error_msg( errno == EPERM || errno == EACCES
+ ? bb_msg_perm_denied_are_you_root
+ : "cannot setup loop device");
+ return errno;
+ }
+
+ // Autodetect bind mounts
+
+ } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
+ vfsflags |= MS_BIND;
+ }
+
+ /* If we know the fstype (or don't need to), jump straight
+ * to the actual mount. */
+
+ if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
+ rc = mount_it_now(mp, vfsflags, filteropts);
+ else {
+ // Loop through filesystem types until mount succeeds
+ // or we run out
+
+ /* Initialize list of block backed filesystems. This has to be
+ * done here so that during "mount -a", mounts after /proc shows up
+ * can autodetect. */
+
+ if (!fslist) {
+ fslist = get_block_backed_filesystems();
+ if (ENABLE_FEATURE_CLEAN_UP && fslist)
+ atexit(delete_block_backed_filesystems);
+ }
+
+ for (fl = fslist; fl; fl = fl->link) {
+ mp->mnt_type = fl->data;
+ rc = mount_it_now(mp, vfsflags, filteropts);
+ if (!rc) break;
+ }
+ }
+
+ // If mount failed, clean up loop file (if any).
+
+ if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
+ del_loop(mp->mnt_fsname);
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(loopFile);
+ free(mp->mnt_fsname);
+ }
+ }
+
+ report_error:
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(filteropts);
+
+ if (rc && errno == EBUSY && ignore_busy) rc = 0;
+ if (rc < 0)
+ /* perror here sometimes says "mounting ... on ... failed: Success" */
+ bb_error_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
+
+ return rc;
+}
+
+// Parse options, if necessary parse fstab/mtab, and call singlemount for
+// each directory to be mounted.
+
+const char must_be_root[] = "you must be root";
+
+int mount_main(int argc, char **argv);
+int mount_main(int argc, char **argv)
+{
+ enum { OPT_ALL = 0x10 };
+
+ char *cmdopts = xstrdup(""), *fstype=0, *storage_path=0;
+ char *opt_o;
+ const char *fstabname;
+ FILE *fstab;
+ int i, j, rc = 0;
+ unsigned opt;
+ struct mntent mtpair[2], *mtcur = mtpair;
+ SKIP_DESKTOP(const int nonroot = 0;)
+ USE_DESKTOP( int nonroot = (getuid() != 0);)
+
+ /* parse long options, like --bind and --move. Note that -o option
+ * and --option are synonymous. Yes, this means --remount,rw works. */
+
+ for (i = j = 0; i < argc; i++) {
+ if (argv[i][0] == '-' && argv[i][1] == '-') {
+ append_mount_options(&cmdopts, argv[i]+2);
+ } else argv[j++] = argv[i];
+ }
+ argv[j] = 0;
+ argc = j;
+
+ // Parse remaining options
+
+ opt = getopt32(argc, argv, "o:t:rwanfvs", &opt_o, &fstype);
+ if (opt & 0x1) append_mount_options(&cmdopts, opt_o); // -o
+ //if (opt & 0x2) // -t
+ if (opt & 0x4) append_mount_options(&cmdopts, "ro"); // -r
+ if (opt & 0x8) append_mount_options(&cmdopts, "rw"); // -w
+ //if (opt & 0x10) // -a
+ if (opt & 0x20) USE_FEATURE_MTAB_SUPPORT(useMtab = 0); // -n
+ if (opt & 0x40) USE_FEATURE_MTAB_SUPPORT(fakeIt = 1); // -f
+ //if (opt & 0x80) // -v: verbose (ignore)
+ //if (opt & 0x100) // -s: sloppy (ignore)
+ argv += optind;
+ argc -= optind;
+
+ // Three or more non-option arguments? Die with a usage message.
+
+ if (argc > 2) bb_show_usage();
+
+ // If we have no arguments, show currently mounted filesystems
+
+ if (!argc) {
+ if (!(opt & OPT_ALL)) {
+ FILE *mountTable = setmntent(bb_path_mtab_file, "r");
+
+ if (!mountTable) bb_error_msg_and_die("no %s", bb_path_mtab_file);
+
+ while (getmntent_r(mountTable, mtpair, bb_common_bufsiz1,
+ sizeof(bb_common_bufsiz1)))
+ {
+ // Don't show rootfs. FIXME: why??
+ // util-linux 2.12a happily shows rootfs...
+ //if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue;
+
+ if (!fstype || !strcmp(mtpair->mnt_type, fstype))
+ printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
+ mtpair->mnt_dir, mtpair->mnt_type,
+ mtpair->mnt_opts);
+ }
+ if (ENABLE_FEATURE_CLEAN_UP) endmntent(mountTable);
+ return EXIT_SUCCESS;
+ }
+ } else storage_path = bb_simplify_path(argv[0]);
+
+ // When we have two arguments, the second is the directory and we can
+ // skip looking at fstab entirely. We can always abspath() the directory
+ // argument when we get it.
+
+ if (argc == 2) {
+ if (nonroot)
+ bb_error_msg_and_die(must_be_root);
+ mtpair->mnt_fsname = argv[0];
+ mtpair->mnt_dir = argv[1];
+ mtpair->mnt_type = fstype;
+ mtpair->mnt_opts = cmdopts;
+ rc = singlemount(mtpair, 0);
+ goto clean_up;
+ }
+
+ i = parse_mount_options(cmdopts, 0);
+ if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
+ bb_error_msg_and_die(must_be_root);
+
+ // If we have a shared subtree flag, don't worry about fstab or mtab.
+
+ if (ENABLE_FEATURE_MOUNT_FLAGS
+ && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
+ ) {
+ rc = mount("", argv[0], "", i, "");
+ if (rc) bb_perror_msg_and_die("%s", argv[0]);
+ goto clean_up;
+ }
+
+ // Open either fstab or mtab
+
+ fstabname = "/etc/fstab";
+ if (i & MS_REMOUNT) {
+ fstabname = bb_path_mtab_file;
+ }
+ fstab = setmntent(fstabname, "r");
+ if (!fstab)
+ bb_perror_msg_and_die("cannot read %s", fstabname);
+
+ // Loop through entries until we find what we're looking for.
+
+ memset(mtpair, 0, sizeof(mtpair));
+ for (;;) {
+ struct mntent *mtnext = (mtcur==mtpair ? mtpair+1 : mtpair);
+
+ // Get next fstab entry
+
+ if (!getmntent_r(fstab, mtcur, bb_common_bufsiz1
+ + (mtcur==mtpair ? sizeof(bb_common_bufsiz1)/2 : 0),
+ sizeof(bb_common_bufsiz1)/2))
+ {
+ // Were we looking for something specific?
+
+ if (argc) {
+
+ // If we didn't find anything, complain.
+
+ if (!mtnext->mnt_fsname)
+ bb_error_msg_and_die("can't find %s in %s",
+ argv[0], fstabname);
+
+ mtcur = mtnext;
+ if (nonroot) {
+ // fstab must have "users" or "user"
+ if (!(parse_mount_options(mtcur->mnt_opts, 0) & MOUNT_USERS))
+ bb_error_msg_and_die(must_be_root);
+ }
+
+ // Mount the last thing we found.
+
+ mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
+ append_mount_options(&(mtcur->mnt_opts), cmdopts);
+ rc = singlemount(mtcur, 0);
+ free(mtcur->mnt_opts);
+ }
+ goto clean_up;
+ }
+
+ /* If we're trying to mount something specific and this isn't it,
+ * skip it. Note we must match both the exact text in fstab (ala
+ * "proc") or a full path from root */
+
+ if (argc) {
+
+ // Is this what we're looking for?
+
+ if (strcmp(argv[0], mtcur->mnt_fsname) &&
+ strcmp(storage_path, mtcur->mnt_fsname) &&
+ strcmp(argv[0], mtcur->mnt_dir) &&
+ strcmp(storage_path, mtcur->mnt_dir)) continue;
+
+ // Remember this entry. Something later may have overmounted
+ // it, and we want the _last_ match.
+
+ mtcur = mtnext;
+
+ // If we're mounting all.
+
+ } else {
+ // Do we need to match a filesystem type?
+ // TODO: support "-t type1,type2"; "-t notype1,type2"
+
+ if (fstype && strcmp(mtcur->mnt_type, fstype)) continue;
+
+ // Skip noauto and swap anyway.
+
+ if (parse_mount_options(mtcur->mnt_opts, 0)
+ & (MOUNT_NOAUTO | MOUNT_SWAP)) continue;
+
+ // No, mount -a won't mount anything,
+ // even user mounts, for mere humans.
+
+ if (nonroot)
+ bb_error_msg_and_die(must_be_root);
+
+ // Mount this thing.
+
+ // NFS mounts want this to be xrealloc-able
+ mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
+ if (singlemount(mtcur, 1)) {
+ /* Count number of failed mounts */
+ rc++;
+ }
+ free(mtcur->mnt_opts);
+ }
+ }
+ if (ENABLE_FEATURE_CLEAN_UP) endmntent(fstab);
+
+clean_up:
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(storage_path);
+ free(cmdopts);
+ }
+
+ return rc;
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/pivot_root.c b/i/pc104/initrd/conf/busybox/util-linux/pivot_root.c
new file mode 100644
index 0000000..2706bd2
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/pivot_root.c
@@ -0,0 +1,27 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * pivot_root.c - Change root file system. Based on util-linux 2.10s
+ *
+ * busyboxed by Evin Robertson
+ * pivot_root syscall stubbed by Erik Andersen, so it will compile
+ * regardless of the kernel being used.
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+#include "busybox.h"
+
+extern int pivot_root(const char * new_root,const char * put_old);
+
+int pivot_root_main(int argc, char **argv);
+int pivot_root_main(int argc, char **argv)
+{
+ if (argc != 3)
+ bb_show_usage();
+
+ if (pivot_root(argv[1], argv[2]) < 0) {
+ /* prints "pivot_root: <strerror text>" */
+ bb_perror_nomsg_and_die();
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/rdate.c b/i/pc104/initrd/conf/busybox/util-linux/rdate.c
new file mode 100644
index 0000000..33cf64e
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/rdate.c
@@ -0,0 +1,71 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * The Rdate command will ask a time server for the RFC 868 time
+ * and optionally set the system time.
+ *
+ * by Sterling Huxley <sterling@europa.com>
+ *
+ * Licensed under GPL v2 or later, see file License for details.
+*/
+
+#include "busybox.h"
+
+enum { RFC_868_BIAS = 2208988800UL };
+
+static void socket_timeout(int sig)
+{
+ bb_error_msg_and_die("timeout connecting to time server");
+}
+
+static time_t askremotedate(const char *host)
+{
+ uint32_t nett;
+ int fd;
+
+ /* Add a timeout for dead or inaccessible servers */
+ alarm(10);
+ signal(SIGALRM, socket_timeout);
+
+ fd = create_and_connect_stream_or_die(host, bb_lookup_port("time", "tcp", 37));
+
+ if (safe_read(fd, (void *)&nett, 4) != 4) /* read time from server */
+ bb_error_msg_and_die("%s did not send the complete time", host);
+ close(fd);
+
+ /* convert from network byte order to local byte order.
+ * RFC 868 time is the number of seconds
+ * since 00:00 (midnight) 1 January 1900 GMT
+ * the RFC 868 time 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT
+ * Subtract the RFC 868 time to get Linux epoch
+ */
+
+ return ntohl(nett) - RFC_868_BIAS;
+}
+
+int rdate_main(int argc, char **argv);
+int rdate_main(int argc, char **argv)
+{
+ time_t remote_time;
+ unsigned long flags;
+
+ opt_complementary = "-1";
+ flags = getopt32(argc, argv, "sp");
+
+ remote_time = askremotedate(argv[optind]);
+
+ if ((flags & 2) == 0) {
+ time_t current_time;
+
+ time(&current_time);
+ if (current_time == remote_time)
+ bb_error_msg("current time matches remote time");
+ else
+ if (stime(&remote_time) < 0)
+ bb_perror_msg_and_die("cannot set time of day");
+ }
+
+ if ((flags & 1) == 0)
+ printf("%s", ctime(&remote_time));
+
+ return EXIT_SUCCESS;
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/readprofile.c b/i/pc104/initrd/conf/busybox/util-linux/readprofile.c
new file mode 100644
index 0000000..a17b9c8
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/readprofile.c
@@ -0,0 +1,237 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * readprofile.c - used to read /proc/profile
+ *
+ * Copyright (C) 1994,1996 Alessandro Rubini (rubini@ipvvis.unipv.it)
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/*
+ * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
+ * - added Native Language Support
+ * 1999-09-01 Stephane Eranian <eranian@cello.hpl.hp.com>
+ * - 64bit clean patch
+ * 3Feb2001 Andrew Morton <andrewm@uow.edu.au>
+ * - -M option to write profile multiplier.
+ * 2001-11-07 Werner Almesberger <wa@almesberger.net>
+ * - byte order auto-detection and -n option
+ * 2001-11-09 Werner Almesberger <wa@almesberger.net>
+ * - skip step size (index 0)
+ * 2002-03-09 John Levon <moz@compsoc.man.ac.uk>
+ * - make maplineno do something
+ * 2002-11-28 Mads Martin Joergensen +
+ * - also try /boot/System.map-`uname -r`
+ * 2003-04-09 Werner Almesberger <wa@almesberger.net>
+ * - fixed off-by eight error and improved heuristics in byte order detection
+ * 2003-08-12 Nikita Danilov <Nikita@Namesys.COM>
+ * - added -s option; example of use:
+ * "readprofile -s -m /boot/System.map-test | grep __d_lookup | sort -n -k3"
+ *
+ * Taken from util-linux and adapted for busybox by
+ * Paul Mundt <lethal@linux-sh.org>.
+ */
+
+#include "busybox.h"
+#include <sys/utsname.h>
+
+#define S_LEN 128
+
+/* These are the defaults */
+static const char defaultmap[] = "/boot/System.map";
+static const char defaultpro[] = "/proc/profile";
+
+int readprofile_main(int argc, char **argv);
+int readprofile_main(int argc, char **argv)
+{
+ FILE *map;
+ const char *mapFile, *proFile, *mult = 0;
+ unsigned long indx = 1;
+ size_t len;
+ uint64_t add0 = 0;
+ unsigned int step;
+ unsigned int *buf, total, fn_len;
+ unsigned long long fn_add, next_add; /* current and next address */
+ char fn_name[S_LEN], next_name[S_LEN]; /* current and next name */
+ char mapline[S_LEN];
+ char mode[8];
+ int optAll = 0, optInfo = 0, optReset = 0;
+ int optVerbose = 0, optNative = 0;
+ int optBins = 0, optSub = 0;
+ int maplineno = 1;
+ int header_printed;
+
+#define next (current^1)
+
+ proFile = defaultpro;
+ mapFile = defaultmap;
+
+ opt_complementary = "nn:aa:bb:ss:ii:rr:vv";
+ getopt32(argc, argv, "M:m:p:nabsirv",
+ &mult, &mapFile, &proFile,
+ &optNative, &optAll, &optBins, &optSub,
+ &optInfo, &optReset, &optVerbose);
+
+ if (optReset || mult) {
+ int multiplier, fd, to_write;
+
+ /*
+ * When writing the multiplier, if the length of the write is
+ * not sizeof(int), the multiplier is not changed
+ */
+ if (mult) {
+ multiplier = xatoi_u(mult);
+ to_write = sizeof(int);
+ } else {
+ multiplier = 0;
+ to_write = 1; /* sth different from sizeof(int) */
+ }
+
+ fd = xopen(defaultpro, O_WRONLY);
+
+ if (full_write(fd, &multiplier, to_write) != to_write)
+ bb_perror_msg_and_die("error writing %s", defaultpro);
+
+ close(fd);
+ return EXIT_SUCCESS;
+ }
+
+ /*
+ * Use an fd for the profiling buffer, to skip stdio overhead
+ */
+ len = INT_MAX;
+ buf = xmalloc_open_read_close(proFile, &len);
+ if (!optNative) {
+ int entries = len/sizeof(*buf);
+ int big = 0, small = 0, i;
+ unsigned *p;
+
+ for (p = buf+1; p < buf+entries; p++) {
+ if (*p & ~0U << (sizeof(*buf)*4))
+ big++;
+ if (*p & ((1 << (sizeof(*buf)*4))-1))
+ small++;
+ }
+ if (big > small) {
+ bb_error_msg("assuming reversed byte order, "
+ "use -n to force native byte order");
+ for (p = buf; p < buf+entries; p++)
+ for (i = 0; i < sizeof(*buf)/2; i++) {
+ unsigned char *b = (unsigned char *) p;
+ unsigned char tmp;
+
+ tmp = b[i];
+ b[i] = b[sizeof(*buf)-i-1];
+ b[sizeof(*buf)-i-1] = tmp;
+ }
+ }
+ }
+
+ step = buf[0];
+ if (optInfo) {
+ printf("Sampling_step: %i\n", step);
+ return EXIT_SUCCESS;
+ }
+
+ total = 0;
+
+ map = xfopen(mapFile, "r");
+
+ while (fgets(mapline, S_LEN, map)) {
+ if (sscanf(mapline, "%llx %s %s", &fn_add, mode, fn_name) != 3)
+ bb_error_msg_and_die("%s(%i): wrong map line",
+ mapFile, maplineno);
+
+ if (!strcmp(fn_name, "_stext")) /* only elf works like this */ {
+ add0 = fn_add;
+ break;
+ }
+ maplineno++;
+ }
+
+ if (!add0)
+ bb_error_msg_and_die("can't find \"_stext\" in %s", mapFile);
+
+ /*
+ * Main loop.
+ */
+ while (fgets(mapline, S_LEN, map)) {
+ unsigned int this = 0;
+
+ if (sscanf(mapline, "%llx %s %s", &next_add, mode, next_name) != 3)
+ bb_error_msg_and_die("%s(%i): wrong map line",
+ mapFile, maplineno);
+
+ header_printed = 0;
+
+ /* ignore any LEADING (before a '[tT]' symbol is found)
+ Absolute symbols */
+ if ((*mode == 'A' || *mode == '?') && total == 0) continue;
+ if (*mode != 'T' && *mode != 't' &&
+ *mode != 'W' && *mode != 'w')
+ break; /* only text is profiled */
+
+ if (indx >= len / sizeof(*buf))
+ bb_error_msg_and_die("profile address out of range. "
+ "Wrong map file?");
+
+ while (indx < (next_add-add0)/step) {
+ if (optBins && (buf[indx] || optAll)) {
+ if (!header_printed) {
+ printf("%s:\n", fn_name);
+ header_printed = 1;
+ }
+ printf("\t%"PRIx64"\t%u\n", (indx - 1)*step + add0, buf[indx]);
+ }
+ this += buf[indx++];
+ }
+ total += this;
+
+ if (optBins) {
+ if (optVerbose || this > 0)
+ printf(" total\t\t\t\t%u\n", this);
+ } else if ((this || optAll) &&
+ (fn_len = next_add-fn_add) != 0) {
+ if (optVerbose)
+ printf("%016llx %-40s %6i %8.4f\n", fn_add,
+ fn_name, this, this/(double)fn_len);
+ else
+ printf("%6i %-40s %8.4f\n",
+ this, fn_name, this/(double)fn_len);
+ if (optSub) {
+ unsigned long long scan;
+
+ for (scan = (fn_add-add0)/step + 1;
+ scan < (next_add-add0)/step; scan++) {
+ unsigned long long addr;
+
+ addr = (scan - 1)*step + add0;
+ printf("\t%#llx\t%s+%#llx\t%u\n",
+ addr, fn_name, addr - fn_add,
+ buf[scan]);
+ }
+ }
+ }
+
+ fn_add = next_add;
+ strcpy(fn_name, next_name);
+
+ maplineno++;
+ }
+
+ /* clock ticks, out of kernel text - probably modules */
+ printf("%6i %s\n", buf[len/sizeof(*buf)-1], "*unknown*");
+
+ /* trailer */
+ if (optVerbose)
+ printf("%016x %-40s %6i %8.4f\n",
+ 0, "total", total, total/(double)(fn_add-add0));
+ else
+ printf("%6i %-40s %8.4f\n",
+ total, "total", total/(double)(fn_add-add0));
+
+ fclose(map);
+ free(buf);
+
+ return EXIT_SUCCESS;
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/setarch.c b/i/pc104/initrd/conf/busybox/util-linux/setarch.c
new file mode 100644
index 0000000..a7a45ec
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/setarch.c
@@ -0,0 +1,53 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Linux32/linux64 allows for changing uname emulation.
+ *
+ * Copyright 2002 Andi Kleen, SuSE Labs.
+ *
+ * Licensed under GPL v2 or later, see file License for details.
+*/
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/personality.h>
+
+#include "busybox.h"
+
+int setarch_main(int ATTRIBUTE_UNUSED argc, char **argv);
+int setarch_main(int ATTRIBUTE_UNUSED argc, char **argv)
+{
+ int pers = -1;
+
+ /* Figure out what personality we are supposed to switch to ...
+ * we can be invoked as either:
+ * argv[0],argv[1] -> "setarch","personality"
+ * argv[0] -> "personality"
+ */
+retry:
+ if (argv[0][5] == '6') /* linux64 */
+ pers = PER_LINUX;
+ else if (argv[0][5] == '3') /* linux32 */
+ pers = PER_LINUX32;
+ else if (pers == -1 && argv[1] != NULL) {
+ pers = PER_LINUX32;
+ ++argv;
+ goto retry;
+ }
+
+ /* make user actually gave us something to do */
+ ++argv;
+ if (argv[0] == NULL)
+ bb_show_usage();
+
+ /* Try to set personality */
+ if (personality(pers) >= 0) {
+
+ /* Try to execute the program */
+ BB_EXECVP(argv[0], argv);
+ }
+
+ bb_perror_msg_and_die("%s", argv[0]);
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/swaponoff.c b/i/pc104/initrd/conf/busybox/util-linux/swaponoff.c
new file mode 100644
index 0000000..8930035
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/swaponoff.c
@@ -0,0 +1,77 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini swapon/swapoff implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under the GPL version 2, see the file LICENSE in this tarball.
+ */
+
+#include "busybox.h"
+#include <mntent.h>
+#include <sys/swap.h>
+
+static int swap_enable_disable(char *device)
+{
+ int status;
+ struct stat st;
+
+ xstat(device, &st);
+
+#if ENABLE_DESKTOP
+ /* test for holes */
+ if (S_ISREG(st.st_mode))
+ if (st.st_blocks * 512 < st.st_size)
+ bb_error_msg("warning: swap file has holes");
+#endif
+
+ if (applet_name[5] == 'n')
+ status = swapon(device, 0);
+ else
+ status = swapoff(device);
+
+ if (status != 0) {
+ bb_perror_msg("%s", device);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int do_em_all(void)
+{
+ struct mntent *m;
+ FILE *f;
+ int err;
+
+ f = setmntent("/etc/fstab", "r");
+ if (f == NULL)
+ bb_perror_msg_and_die("/etc/fstab");
+
+ err = 0;
+ while ((m = getmntent(f)) != NULL)
+ if (strcmp(m->mnt_type, MNTTYPE_SWAP) == 0)
+ err += swap_enable_disable(m->mnt_fsname);
+
+ endmntent(f);
+
+ return err;
+}
+
+int swap_on_off_main(int argc, char **argv);
+int swap_on_off_main(int argc, char **argv)
+{
+ int ret;
+
+ if (argc == 1)
+ bb_show_usage();
+
+ ret = getopt32(argc, argv, "a");
+ if (ret)
+ return do_em_all();
+
+ /* ret = 0; redundant */
+ while (*++argv)
+ ret += swap_enable_disable(*argv);
+ return ret;
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/switch_root.c b/i/pc104/initrd/conf/busybox/util-linux/switch_root.c
new file mode 100644
index 0000000..5a01fd6
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/switch_root.c
@@ -0,0 +1,123 @@
+/* vi: set sw=4 ts=4: */
+/* Copyright 2005 Rob Landley <rob@landley.net>
+ *
+ * Switch from rootfs to another filesystem as the root of the mount tree.
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+#include "busybox.h"
+#include <sys/vfs.h>
+
+
+// Make up for header deficiencies.
+
+#ifndef RAMFS_MAGIC
+#define RAMFS_MAGIC 0x858458f6
+#endif
+
+#ifndef TMPFS_MAGIC
+#define TMPFS_MAGIC 0x01021994
+#endif
+
+#ifndef MS_MOVE
+#define MS_MOVE 8192
+#endif
+
+dev_t rootdev;
+
+// Recursively delete contents of rootfs.
+
+static void delete_contents(const char *directory)
+{
+ DIR *dir;
+ struct dirent *d;
+ struct stat st;
+
+ // Don't descend into other filesystems
+ if (lstat(directory, &st) || st.st_dev != rootdev) return;
+
+ // Recursively delete the contents of directories.
+ if (S_ISDIR(st.st_mode)) {
+ if((dir = opendir(directory))) {
+ while ((d = readdir(dir))) {
+ char *newdir=d->d_name;
+
+ // Skip . and ..
+ if(*newdir=='.' && (!newdir[1] || (newdir[1]=='.' && !newdir[2])))
+ continue;
+
+ // Recurse to delete contents
+ newdir = alloca(strlen(directory) + strlen(d->d_name) + 2);
+ sprintf(newdir, "%s/%s", directory, d->d_name);
+ delete_contents(newdir);
+ }
+ closedir(dir);
+
+ // Directory should now be empty. Zap it.
+ rmdir(directory);
+ }
+
+ // It wasn't a directory. Zap it.
+
+ } else unlink(directory);
+}
+
+int switch_root_main(int argc, char *argv[]);
+int switch_root_main(int argc, char *argv[])
+{
+ char *newroot, *console=NULL;
+ struct stat st1, st2;
+ struct statfs stfs;
+
+ // Parse args (-c console)
+
+ opt_complementary = "-2";
+ getopt32(argc, argv, "c:", &console);
+
+ // Change to new root directory and verify it's a different fs.
+
+ newroot=argv[optind++];
+
+ if (chdir(newroot) || lstat(".", &st1) || lstat("/", &st2) ||
+ st1.st_dev == st2.st_dev)
+ {
+ bb_error_msg_and_die("bad newroot %s", newroot);
+ }
+ rootdev=st2.st_dev;
+
+ // Additional sanity checks: we're about to rm -rf /, so be REALLY SURE
+ // we mean it. (I could make this a CONFIG option, but I would get email
+ // from all the people who WILL eat their filesystemss.)
+
+ if (lstat("/init", &st1) || !S_ISREG(st1.st_mode) || statfs("/", &stfs) ||
+ (stfs.f_type != RAMFS_MAGIC && stfs.f_type != TMPFS_MAGIC) ||
+ getpid() != 1)
+ {
+ bb_error_msg_and_die("not rootfs");
+ }
+
+ // Zap everything out of rootdev
+
+ delete_contents("/");
+
+ // Overmount / with newdir and chroot into it. The chdir is needed to
+ // recalculate "." and ".." links.
+
+ if (mount(".", "/", NULL, MS_MOVE, NULL) || chroot(".") || chdir("/"))
+ bb_error_msg_and_die("moving root");
+
+ // If a new console specified, redirect stdin/stdout/stderr to that.
+
+ if (console) {
+ close(0);
+ if(open(console, O_RDWR) < 0)
+ bb_error_msg_and_die("bad console '%s'", console);
+ dup2(0, 1);
+ dup2(0, 2);
+ }
+
+ // Exec real init. (This is why we must be pid 1.)
+ execv(argv[optind], argv+optind);
+ bb_error_msg_and_die("bad init '%s'", argv[optind]);
+}
diff --git a/i/pc104/initrd/conf/busybox/util-linux/umount.c b/i/pc104/initrd/conf/busybox/util-linux/umount.c
new file mode 100644
index 0000000..4ea15d9
--- /dev/null
+++ b/i/pc104/initrd/conf/busybox/util-linux/umount.c
@@ -0,0 +1,152 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini umount implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2005 by Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+#include "busybox.h"
+#include <mntent.h>
+#include <getopt.h>
+
+#define OPTION_STRING "flDnravd"
+#define OPT_FORCE 1
+#define OPT_LAZY 2
+#define OPT_DONTFREELOOP 4
+#define OPT_NO_MTAB 8
+#define OPT_REMOUNT 16
+#define OPT_ALL (ENABLE_FEATURE_UMOUNT_ALL ? 32 : 0)
+
+int umount_main(int argc, char **argv);
+int umount_main(int argc, char **argv)
+{
+ int doForce;
+ char path[2*PATH_MAX];
+ struct mntent me;
+ FILE *fp;
+ int status = EXIT_SUCCESS;
+ unsigned opt;
+ struct mtab_list {
+ char *dir;
+ char *device;
+ struct mtab_list *next;
+ } *mtl, *m;
+
+ /* Parse any options */
+
+ opt = getopt32(argc, argv, OPTION_STRING);
+
+ argc -= optind;
+ argv += optind;
+
+ doForce = MAX((opt & OPT_FORCE), (opt & OPT_LAZY));
+
+ /* Get a list of mount points from mtab. We read them all in now mostly
+ * for umount -a (so we don't have to worry about the list changing while
+ * we iterate over it, or about getting stuck in a loop on the same failing
+ * entry. Notice that this also naturally reverses the list so that -a
+ * umounts the most recent entries first. */
+
+ m = mtl = 0;
+
+ /* If we're umounting all, then m points to the start of the list and
+ * the argument list should be empty (which will match all). */
+
+ fp = setmntent(bb_path_mtab_file, "r");
+ if (!fp) {
+ if (opt & OPT_ALL)
+ bb_error_msg_and_die("cannot open %s", bb_path_mtab_file);
+ } else {
+ while (getmntent_r(fp, &me, path, sizeof(path))) {
+ m = xmalloc(sizeof(struct mtab_list));
+ m->next = mtl;
+ m->device = xstrdup(me.mnt_fsname);
+ m->dir = xstrdup(me.mnt_dir);
+ mtl = m;
+ }
+ endmntent(fp);
+ }
+
+ /* If we're not umounting all, we need at least one argument. */
+ if (!(opt & OPT_ALL)) {
+ m = 0;
+ if (!argc) bb_show_usage();
+ }
+
+ // Loop through everything we're supposed to umount, and do so.
+ for (;;) {
+ int curstat;
+ char *zapit = *argv;
+
+ // Do we already know what to umount this time through the loop?
+ if (m) safe_strncpy(path, m->dir, PATH_MAX);
+ // For umount -a, end of mtab means time to exit.
+ else if (opt & OPT_ALL) break;
+ // Get next command line argument (and look it up in mtab list)
+ else if (!argc--) break;
+ else {
+ argv++;
+ realpath(zapit, path);
+ for (m = mtl; m; m = m->next)
+ if (!strcmp(path, m->dir) || !strcmp(path, m->device))
+ break;
+ }
+ // If we couldn't find this sucker in /etc/mtab, punt by passing our
+ // command line argument straight to the umount syscall. Otherwise,
+ // umount the directory even if we were given the block device.
+ if (m) zapit = m->dir;
+
+ // Let's ask the thing nicely to unmount.
+ curstat = umount(zapit);
+
+ // Force the unmount, if necessary.
+ if (curstat && doForce) {
+ curstat = umount2(zapit, doForce);
+ if (curstat)
+ bb_error_msg("forced umount of %s failed!", zapit);
+ }
+
+ // If still can't umount, maybe remount read-only?
+ if (curstat && (opt & OPT_REMOUNT) && errno == EBUSY && m) {
+ curstat = mount(m->device, zapit, NULL, MS_REMOUNT|MS_RDONLY, NULL);
+ bb_error_msg(curstat ? "cannot remount %s read-only" :
+ "%s busy - remounted read-only", m->device);
+ }
+
+ if (curstat) {
+ status = EXIT_FAILURE;
+ bb_perror_msg("cannot umount %s", zapit);
+ } else {
+ /* De-allocate the loop device. This ioctl should be ignored on
+ * any non-loop block devices. */
+ if (ENABLE_FEATURE_MOUNT_LOOP && !(opt & OPT_DONTFREELOOP) && m)
+ del_loop(m->device);
+ if (ENABLE_FEATURE_MTAB_SUPPORT && !(opt & OPT_NO_MTAB) && m)
+ erase_mtab(m->dir);
+ }
+
+ // Find next matching mtab entry for -a or umount /dev
+ // Note this means that "umount /dev/blah" will unmount all instances
+ // of /dev/blah, not just the most recent.
+ while (m && (m = m->next))
+ if ((opt & OPT_ALL) || !strcmp(path, m->device))
+ break;
+ }
+
+ // Free mtab list if necessary
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ while (mtl) {
+ m = mtl->next;
+ free(mtl->device);
+ free(mtl->dir);
+ free(mtl);
+ mtl = m;
+ }
+ }
+
+ return status;
+}