summaryrefslogtreecommitdiff
path: root/release/src/router/busybox/util-linux
diff options
context:
space:
mode:
Diffstat (limited to 'release/src/router/busybox/util-linux')
-rw-r--r--[-rwxr-xr-x]release/src/router/busybox/util-linux/Config.in839
-rw-r--r--release/src/router/busybox/util-linux/Kbuild39
-rw-r--r--release/src/router/busybox/util-linux/Makefile30
-rwxr-xr-xrelease/src/router/busybox/util-linux/Makefile.in51
-rw-r--r--release/src/router/busybox/util-linux/acpid.c167
-rw-r--r--release/src/router/busybox/util-linux/blkid.c18
-rw-r--r--release/src/router/busybox/util-linux/dmesg.c132
-rw-r--r--release/src/router/busybox/util-linux/fbset.c587
-rw-r--r--release/src/router/busybox/util-linux/fdflush.c54
-rw-r--r--release/src/router/busybox/util-linux/fdformat.c197
-rw-r--r--release/src/router/busybox/util-linux/fdisk.c5877
-rw-r--r--release/src/router/busybox/util-linux/fdisk_aix.c73
-rw-r--r--release/src/router/busybox/util-linux/fdisk_osf.c1052
-rw-r--r--release/src/router/busybox/util-linux/fdisk_sgi.c886
-rw-r--r--release/src/router/busybox/util-linux/fdisk_sun.c728
-rw-r--r--release/src/router/busybox/util-linux/findfs.c38
-rw-r--r--release/src/router/busybox/util-linux/freeramdisk.c67
-rw-r--r--release/src/router/busybox/util-linux/fsck_minix.c1313
-rw-r--r--release/src/router/busybox/util-linux/getopt.c583
-rw-r--r--release/src/router/busybox/util-linux/hexdump.c203
-rw-r--r--release/src/router/busybox/util-linux/hwclock.c299
-rw-r--r--release/src/router/busybox/util-linux/ipcrm.c220
-rw-r--r--release/src/router/busybox/util-linux/ipcs.c621
-rw-r--r--release/src/router/busybox/util-linux/losetup.c118
-rw-r--r--release/src/router/busybox/util-linux/mdev.c544
-rw-r--r--release/src/router/busybox/util-linux/minix.h98
-rw-r--r--release/src/router/busybox/util-linux/mkfs_minix.c882
-rw-r--r--release/src/router/busybox/util-linux/mkfs_vfat.c614
-rw-r--r--release/src/router/busybox/util-linux/mkswap.c493
-rw-r--r--release/src/router/busybox/util-linux/more.c285
-rw-r--r--release/src/router/busybox/util-linux/mount.c2251
-rw-r--r--release/src/router/busybox/util-linux/nfsmount.c1024
-rw-r--r--release/src/router/busybox/util-linux/nfsmount.h242
-rw-r--r--release/src/router/busybox/util-linux/pivot_root.c32
-rw-r--r--release/src/router/busybox/util-linux/rdate.c95
-rw-r--r--release/src/router/busybox/util-linux/rdev.c24
-rw-r--r--release/src/router/busybox/util-linux/readprofile.c247
-rw-r--r--release/src/router/busybox/util-linux/rtcwake.c201
-rw-r--r--release/src/router/busybox/util-linux/script.c186
-rw-r--r--release/src/router/busybox/util-linux/setarch.c48
-rw-r--r--release/src/router/busybox/util-linux/swaponoff.c145
-rw-r--r--release/src/router/busybox/util-linux/switch_root.c115
-rw-r--r--release/src/router/busybox/util-linux/umount.c414
-rw-r--r--release/src/router/busybox/util-linux/volume_id/Kbuild42
-rw-r--r--release/src/router/busybox/util-linux/volume_id/cramfs.c59
-rw-r--r--release/src/router/busybox/util-linux/volume_id/ext.c74
-rw-r--r--release/src/router/busybox/util-linux/volume_id/fat.c332
-rw-r--r--release/src/router/busybox/util-linux/volume_id/get_devname.c252
-rw-r--r--release/src/router/busybox/util-linux/volume_id/hfs.c292
-rw-r--r--release/src/router/busybox/util-linux/volume_id/iso9660.c120
-rw-r--r--release/src/router/busybox/util-linux/volume_id/jfs.c60
-rw-r--r--release/src/router/busybox/util-linux/volume_id/linux_raid.c80
-rw-r--r--release/src/router/busybox/util-linux/volume_id/linux_swap.c74
-rw-r--r--release/src/router/busybox/util-linux/volume_id/luks.c100
-rw-r--r--release/src/router/busybox/util-linux/volume_id/ntfs.c194
-rw-r--r--release/src/router/busybox/util-linux/volume_id/ocfs2.c106
-rw-r--r--release/src/router/busybox/util-linux/volume_id/reiserfs.c113
-rw-r--r--release/src/router/busybox/util-linux/volume_id/romfs.c55
-rw-r--r--release/src/router/busybox/util-linux/volume_id/sysv.c126
-rw-r--r--release/src/router/busybox/util-linux/volume_id/udf.c173
-rw-r--r--release/src/router/busybox/util-linux/volume_id/unused_highpoint.c86
-rw-r--r--release/src/router/busybox/util-linux/volume_id/unused_hpfs.c49
-rw-r--r--release/src/router/busybox/util-linux/volume_id/unused_isw_raid.c58
-rw-r--r--release/src/router/busybox/util-linux/volume_id/unused_lsi_raid.c52
-rw-r--r--release/src/router/busybox/util-linux/volume_id/unused_lvm.c87
-rw-r--r--release/src/router/busybox/util-linux/volume_id/unused_mac.c123
-rw-r--r--release/src/router/busybox/util-linux/volume_id/unused_minix.c75
-rw-r--r--release/src/router/busybox/util-linux/volume_id/unused_msdos.c193
-rw-r--r--release/src/router/busybox/util-linux/volume_id/unused_nvidia_raid.c56
-rw-r--r--release/src/router/busybox/util-linux/volume_id/unused_promise_raid.c63
-rw-r--r--release/src/router/busybox/util-linux/volume_id/unused_silicon_raid.c69
-rw-r--r--release/src/router/busybox/util-linux/volume_id/unused_ufs.c206
-rw-r--r--release/src/router/busybox/util-linux/volume_id/unused_via_raid.c68
-rw-r--r--release/src/router/busybox/util-linux/volume_id/util.c282
-rw-r--r--release/src/router/busybox/util-linux/volume_id/volume_id.c244
-rw-r--r--release/src/router/busybox/util-linux/volume_id/volume_id_internal.h227
-rw-r--r--release/src/router/busybox/util-linux/volume_id/xfs.c60
77 files changed, 16639 insertions, 9743 deletions
diff --git a/release/src/router/busybox/util-linux/Config.in b/release/src/router/busybox/util-linux/Config.in
index 42708c93..e5c053fc 100755..100644
--- a/release/src/router/busybox/util-linux/Config.in
+++ b/release/src/router/busybox/util-linux/Config.in
@@ -5,346 +5,869 @@
menu "Linux System Utilities"
+config ACPID
+ bool "acpid"
+ default n
+ help
+ acpid listens to ACPI events coming either in textual form from
+ /proc/acpi/event (though it is marked deprecated it is still widely
+ used and _is_ a standard) or in binary form from specified evdevs
+ (just use /dev/input/event*).
+
+ It parses the event to retrieve ACTION and a possible PARAMETER.
+ It then spawns /etc/acpi/<ACTION>[/<PARAMETER>] either via run-parts
+ (if the resulting path is a directory) or directly as an executable.
-config CONFIG_DMESG
+ N.B. acpid relies on run-parts so have the latter installed.
+
+config FEATURE_ACPID_COMPAT
+ bool "Accept and ignore redundant options"
+ default n
+ depends on ACPID
+ help
+ Accept and ignore compatibility options -g -m -s -S -v.
+
+config BLKID
+ bool "blkid"
+ default n
+ select VOLUMEID
+ help
+ Lists labels and UUIDs of all filesystems.
+ WARNING:
+ With all submodules selected, it will add ~8k to busybox.
+
+config DMESG
bool "dmesg"
default n
help
- dmesg is used to examine or control the kernel ring buffer. When the
+ 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
+ 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
+ are also logged to the system console. Enable this option if you
wish to enable the 'dmesg' utility.
-config CONFIG_FBSET
+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 graphic display. Enable this option if you wish
- to enable the 'fbset' utility.
-
+ 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 CONFIG_FEATURE_FBSET_FANCY
- bool " Turn on extra fbset options"
+config FEATURE_FBSET_FANCY
+ bool "Turn on extra fbset options"
default n
- depends on CONFIG_FBSET
+ depends on FBSET
help
This option enables extended fbset options, allowing one to set the
- framebuffer size, color depth, etc. interface to access a graphic
- display. Enable this option if you wish to enable extended fbset
+ framebuffer size, color depth, etc. interface to access a graphics
+ display. Enable this option if you wish to enable extended fbset
options.
-config CONFIG_FEATURE_FBSET_READMODE
- bool " Turn on fbset readmode support"
+config FEATURE_FBSET_READMODE
+ bool "Turn on fbset readmode support"
default n
- depends on CONFIG_FBSET
+ 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 CONFIG_FDFLUSH
+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
+ 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
+ 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
- say leave this disabled.
+ you change a disk. Most people have working hardware and can safely
+ leave this disabled.
-config CONFIG_FDFORMAT
+config FDFORMAT
bool "fdformat"
default n
help
- Fdformat is used to low-level format a floppy disk.
+ fdformat is used to low-level format a floppy disk.
-config CONFIG_FDISK
+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
+ 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 CONFIG_FEATURE_FDISK_WRITABLE
- bool " Write support"
+config FDISK_SUPPORT_LARGE_DISKS
+ bool "Support over 4GB disks"
default y
- depends on CONFIG_FDISK
+ 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
+ and write those changes out to disk. If you leave this option
disabled, you will only be able to view the partition table.
-config CONFIG_FEATURE_AIX_LABEL
- bool " Support AIX disklabels"
+config FEATURE_AIX_LABEL
+ bool "Support AIX disklabels"
default n
- depends on CONFIG_FDISK && CONFIG_FEATURE_FDISK_WRITABLE
+ 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 CONFIG_FEATURE_SGI_LABEL
- bool " Support SGI disklabels"
+config FEATURE_SGI_LABEL
+ bool "Support SGI disklabels"
default n
- depends on CONFIG_FDISK && CONFIG_FEATURE_FDISK_WRITABLE
+ 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 CONFIG_FEATURE_SUN_LABEL
- bool " Support SUN disklabels"
+config FEATURE_SUN_LABEL
+ bool "Support SUN disklabels"
default n
- depends on CONFIG_FDISK && CONFIG_FEATURE_FDISK_WRITABLE
+ 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 CONFIG_FEATURE_OSF_LABEL
- bool " Support BSD disklabels"
+config FEATURE_OSF_LABEL
+ bool "Support BSD disklabels"
default n
- depends on CONFIG_FDISK && CONFIG_FEATURE_FDISK_WRITABLE
+ 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 CONFIG_FEATURE_FDISK_ADVANCED
- bool " Support expert mode"
+config FEATURE_FDISK_ADVANCED
+ bool "Support expert mode"
default n
- depends on CONFIG_FDISK && CONFIG_FEATURE_FDISK_WRITABLE
+ 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
+ partition, and similarly evil things. Unless you have a very good
reason you would be wise to leave this disabled.
-config CONFIG_FREERAMDISK
+config FINDFS
+ bool "findfs"
+ default n
+ select VOLUMEID
+ help
+ Prints the name of a filesystem with given label or UUID.
+ WARNING:
+ With all submodules selected, it will add ~8k to busybox.
+
+config FREERAMDISK
bool "freeramdisk"
default n
help
- Linux allows you to create ramdisks. This utility allows you to
+ 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
+ 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
+ ramdisk. If you have no use for freeing memory from a ramdisk, leave
this disabled.
-config CONFIG_FSCK_MINIX
+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 encounted corruption if it is not properly unmounted or if the
- power goes off in the middle of a write. This utility allows you to
+ 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 CONFIG_MKFS_MINIX
+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.
+ 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 CONFIG_FSCK_MINIX || CONFIG_MKFS_MINIX
+ depends on FSCK_MINIX || MKFS_MINIX
-config CONFIG_FEATURE_MINIX2
- bool " Support Minix fs v2 (fsck_minix/mkfs_minix)"
+config FEATURE_MINIX2
+ bool "Support Minix fs v2 (fsck_minix/mkfs_minix)"
default y
- depends on CONFIG_FSCK_MINIX || CONFIG_MKFS_MINIX
+ 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.
+ 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 CONFIG_GETOPT
+config MKFS_VFAT
+ bool "mkfs_vfat"
+ default n
+ help
+ Utility to create FAT32 filesystems.
+
+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
+ 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
+ written by others, this utility may be for you. Most people will
wisely leave this disabled.
-config CONFIG_HEXDUMP
+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 CONFIG_HWCLOCK
+config FEATURE_HEXDUMP_REVERSE
+ bool "Support -R, reverse of 'hexdump -Cv'"
+ default n
+ depends on HEXDUMP
+ help
+ The hexdump utility is used to display binary data in an ascii
+ readable way. This option creates binary data from an ascii input.
+ NB: this option is non-standard. It's unwise to use it in scripts
+ aimed to be portable.
+
+config HD
+ bool "hd"
+ default n
+ select HEXDUMP
+ help
+ hd is an alias to hexdump -C.
+
+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 correct time in
- the hardware close, so the hardware will keep the correct time
- when Linux is _not_ running.
+ 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 CONFIG_FEATURE_HWCLOCK_LONGOPTIONS
- bool " Support long options (--hctosys,...)"
+config FEATURE_HWCLOCK_LONG_OPTIONS
+ bool "Support long options (--hctosys,...)"
default n
- depends on CONFIG_HWCLOCK
+ depends on HWCLOCK && GETOPT_LONG
help
- By default, the hwclock utility only uses short options. If you
- are overly fond of the long options, such as --hctosys, --utc, etc)
+ 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 CONFIG_LOSETUP
+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.
+
+ 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
+ file or block device, and to query the status of a loop device. This
version does not currently support enabling data encryption.
-config CONFIG_MKSWAP
+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_RENAME
+ bool "Support subdirs/symlinks"
+ default n
+ depends on FEATURE_MDEV_CONF
+ help
+ Add support for renaming devices and creating symlinks.
+
+ For more information, please see docs/mdev.txt
+
+config FEATURE_MDEV_RENAME_REGEXP
+ bool "Support regular expressions substitutions when renaming device"
+ default n
+ depends on FEATURE_MDEV_RENAME
+ help
+ Add support for regular expressions substitutions when renaming
+ device.
+
+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 FEATURE_MDEV_LOAD_FIRMWARE
+ bool "Support loading of firmwares"
+ default n
+ depends on MDEV
+ help
+ Some devices need to load firmware before they can be usable.
+
+ These devices will request userspace look up the files in
+ /lib/firmware/ and if it exists, send it to the kernel for
+ loading into the hardware.
+
+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
+ 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
+ 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.
+ 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 CONFIG_MORE
+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
+ 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
+ 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 CONFIG_FEATURE_USE_TERMIOS
- bool " Use termios to manipulate the screen"
+config FEATURE_USE_TERMIOS
+ bool "Use termios to manipulate the screen"
default y
- depends on CONFIG_MORE
+ depends on MORE || TOP
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 with be especially primitive and
+ 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 CONFIG_PIVOT_ROOT
+config VOLUMEID
+ bool #No description makes it a hidden option
+ default n
+
+config FEATURE_VOLUMEID_EXT
+ bool "Ext filesystem"
+ default n
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_REISERFS
+ bool "Reiser filesystem"
+ default n
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_FAT
+ bool "fat filesystem"
+ default n
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_HFS
+ bool "hfs filesystem"
+ default n
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_JFS
+ bool "jfs filesystem"
+ default n
+ depends on VOLUMEID
+ help
+ TODO
+
+### config FEATURE_VOLUMEID_UFS
+### bool "ufs filesystem"
+### default n
+### depends on VOLUMEID
+### help
+### TODO
+
+config FEATURE_VOLUMEID_XFS
+ bool "xfs filesystem"
+ default n
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_NTFS
+ bool "ntfs filesystem"
+ default n
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_ISO9660
+ bool "iso9660 filesystem"
+ default n
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_UDF
+ bool "udf filesystem"
+ default n
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_LUKS
+ bool "luks filesystem"
+ default n
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_LINUXSWAP
+ bool "linux swap filesystem"
+ default n
+ depends on VOLUMEID
+ help
+ TODO
+
+### config FEATURE_VOLUMEID_LVM
+### bool "lvm"
+### default n
+### depends on VOLUMEID
+### help
+### TODO
+
+config FEATURE_VOLUMEID_CRAMFS
+ bool "cramfs filesystem"
+ default n
+ depends on VOLUMEID
+ help
+ TODO
+
+### config FEATURE_VOLUMEID_HPFS
+### bool "hpfs filesystem"
+### default n
+### depends on VOLUMEID
+### help
+### TODO
+
+config FEATURE_VOLUMEID_ROMFS
+ bool "romfs filesystem"
+ default n
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_SYSV
+ bool "sysv filesystem"
+ default n
+ depends on VOLUMEID
+ help
+ TODO
+
+### config FEATURE_VOLUMEID_MINIX
+### bool "minix filesystem"
+### default n
+### depends on VOLUMEID
+### help
+### TODO
+
+### These only detect partition tables - not used (yet?)
+### config FEATURE_VOLUMEID_MAC
+### bool "mac filesystem"
+### default n
+### depends on VOLUMEID
+### help
+### TODO
+###
+### config FEATURE_VOLUMEID_MSDOS
+### bool "msdos filesystem"
+### default n
+### depends on VOLUMEID
+### help
+### TODO
+
+config FEATURE_VOLUMEID_OCFS2
+ bool "ocfs2 filesystem"
+ default n
+ depends on VOLUMEID
+ help
+ TODO
+
+### config FEATURE_VOLUMEID_HIGHPOINTRAID
+### bool "highpoint raid"
+### default n
+### depends on VOLUMEID
+### help
+### TODO
+
+### config FEATURE_VOLUMEID_ISWRAID
+### bool "intel raid"
+### default n
+### depends on VOLUMEID
+### help
+### TODO
+
+### config FEATURE_VOLUMEID_LSIRAID
+### bool "lsi raid"
+### default n
+### depends on VOLUMEID
+### help
+### TODO
+
+### config FEATURE_VOLUMEID_VIARAID
+### bool "via raid"
+### default n
+### depends on VOLUMEID
+### help
+### TODO
+
+### config FEATURE_VOLUMEID_SILICONRAID
+### bool "silicon raid"
+### default n
+### depends on VOLUMEID
+### help
+### TODO
+
+### config FEATURE_VOLUMEID_NVIDIARAID
+### bool "nvidia raid"
+### default n
+### depends on VOLUMEID
+### help
+### TODO
+
+### config FEATURE_VOLUMEID_PROMISERAID
+### bool "promise raid"
+### default n
+### depends on VOLUMEID
+### help
+### TODO
+
+config FEATURE_VOLUMEID_LINUXRAID
+ bool "linuxraid"
+ default n
+ depends on VOLUMEID
+ help
+ TODO
+
+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_FAKE
+ bool "Support option -f"
+ default n
+ depends on MOUNT
+ help
+ Enable support for faking a file system mount.
+
+config FEATURE_MOUNT_VERBOSE
+ bool "Support option -v"
+ default n
+ depends on MOUNT
+ help
+ Enable multi-level -v[vv...] verbose messages. Useful if you
+ debug mount problems and want to see what is exactly passed
+ to the kernel.
+
+config FEATURE_MOUNT_HELPERS
+ bool "Support mount helpers"
+ default n
+ depends on MOUNT
+ help
+ Enable mounting of virtual file systems via external helpers.
+ E.g. "mount obexfs#-b00.11.22.33.44.55 /mnt" will in effect call
+ "obexfs -b00.11.22.33.44.55 /mnt"
+ Also "mount -t sometype [-o opts] fs /mnt" will try
+ "sometype [-o opts] fs /mnt" if simple mount syscall fails.
+ The idea is to use such virtual filesystems in /etc/fstab.
+
+config FEATURE_MOUNT_LABEL
+ bool "Support specifiying devices by label or UUID"
+ default n
+ depends on MOUNT
+ select VOLUMEID
+ help
+ This allows for specifying a device by label or uuid, rather than by
+ name. This feature utilizes the same functionality as blkid/findfs.
+
+config FEATURE_MOUNT_NFS
+ bool "Support mounting NFS file systems"
+ default n
+ depends on MOUNT
+ select 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
+ 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'.
-config CONFIG_RDATE
+ 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 syncronize the date and time of your
+ 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 CONFIG_SWAPONOFF
+config RDEV
+ bool "rdev"
+ default n
+ help
+ Print the device node associated with the filesystem mounted at '/'.
+
+config READPROFILE
+ bool "readprofile"
+ default n
+ help
+ This allows you to parse /proc/profile for basic profiling.
+
+config RTCWAKE
+ bool "rtcwake"
+ default n
+ help
+ Enter a system sleep state until specified wakeup time.
+
+config SCRIPT
+ bool "script"
+ default n
+ help
+ The script makes typescript of terminal session.
+
+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'
+ 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
+ space. If you are not using any swap space, you can leave this
option disabled.
-config CONFIG_MOUNT
- bool "mount"
+config FEATURE_SWAPON_PRI
+ bool "Support priority option -p"
default n
+ depends on SWAPONOFF
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.
+ Enable support for setting swap device priority in swapon.
-config CONFIG_NFSMOUNT
- bool " Support mounting nfs file systems"
+config SWITCH_ROOT
+ bool "switch_root"
default n
- depends on CONFIG_MOUNT
help
- Enable mounting of NFS file systems.
+ 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.
-config CONFIG_UMOUNT
+ * 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'.
+ 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 CONFIG_FEATURE_MOUNT_FORCE
- bool " Support forced filesystem unmounting"
+config FEATURE_UMOUNT_ALL
+ bool "Support option -a"
default n
- depends on CONFIG_UMOUNT
+ depends on UMOUNT
help
- This allows you to _force_ a filesystem to be umounted. This is generally
- only useful when you want to get rid of an unreachable NFS system.
+ Support -a option to unmount all currently mounted filesystems.
comment "Common options for mount/umount"
- depends on CONFIG_MOUNT || CONFIG_UMOUNT
+ depends on MOUNT || UMOUNT
-config CONFIG_FEATURE_MOUNT_LOOP
- bool " Support for loop devices"
+config FEATURE_MOUNT_LOOP
+ bool "Support loopback mounts"
default n
- depends on CONFIG_MOUNT || CONFIG_UMOUNT
- help
- Enabling this feature allows mount to use the '-o' loop options,
- which lets you loop mount files. Mount will automagically setup and
- free the necessary loop devices so you do not need to mess with the
- 'losetup' utility unless you really want to. This is really only useful
- if you plan to loop mount files.
-
-config CONFIG_FEATURE_MTAB_SUPPORT
- bool " Support for a real /etc/mtab (instead of /proc/mounts)"
+ 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 CONFIG_MOUNT || CONFIG_UMOUNT
- help
- If your root filesystem is writable and you wish to have the 'mount'
- utility create an mtab file listing the filesystems which have been
- mounted then you should enable this option. Most people that use
- BusyBox have a read-only root filesystem, so they will leave this
- option disabled and BusyBox will use the /proc/mounts file.
-
-config CONFIG_FEATURE_MTAB_FILENAME
- string " mtab file location"
- default "/etc/mtab"
- depends on CONFIG_FEATURE_MTAB_SUPPORT
- help
- Some people have a read only root filesystem, but they also wish to
- have the 'mount' utility create an mtab file listing the filesystems
- which have been mounted. This option allows you to specify an alternative
- location for the mtab file, such as /var/mtab, or /tmp/mtab. The default
- value is /etc/mtab, which is where this file is located on most desktop
- Linux systems.
+ depends on MOUNT || UMOUNT
+ select FEATURE_MOUNT_FAKE
+ 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/release/src/router/busybox/util-linux/Kbuild b/release/src/router/busybox/util-linux/Kbuild
new file mode 100644
index 00000000..ac071c62
--- /dev/null
+++ b/release/src/router/busybox/util-linux/Kbuild
@@ -0,0 +1,39 @@
+# 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_ACPID) += acpid.o
+lib-$(CONFIG_BLKID) += blkid.o
+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_FINDFS) += findfs.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_MKFS_VFAT) += mkfs_vfat.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_RDEV) += rdev.o
+lib-$(CONFIG_READPROFILE) += readprofile.o
+lib-$(CONFIG_RTCWAKE) += rtcwake.o
+lib-$(CONFIG_SCRIPT) += script.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/release/src/router/busybox/util-linux/Makefile b/release/src/router/busybox/util-linux/Makefile
deleted file mode 100644
index d2e49623..00000000
--- a/release/src/router/busybox/util-linux/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-# Makefile for busybox
-#
-# Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-
-TOPDIR:= ../
-UTILLINUX_DIR:=./
-include $(TOPDIR).config
-include $(TOPDIR)Rules.mak
-include Makefile.in
-all: $(libraries-y)
--include $(TOPDIR).depend
-
-clean:
- rm -f *.o *.a $(AR_TARGET)
-
diff --git a/release/src/router/busybox/util-linux/Makefile.in b/release/src/router/busybox/util-linux/Makefile.in
deleted file mode 100755
index 8cd5f1bd..00000000
--- a/release/src/router/busybox/util-linux/Makefile.in
+++ /dev/null
@@ -1,51 +0,0 @@
-# Makefile for busybox
-#
-# Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-
-UTILLINUX_AR:=util-linux.a
-ifndef $(UTILLINUX_DIR)
-UTILLINUX_DIR:=$(TOPDIR)util-linux/
-endif
-
-UTILLINUX-:=
-UTILLINUX-$(CONFIG_DMESG) += dmesg.o
-UTILLINUX-$(CONFIG_FBSET) += fbset.o
-UTILLINUX-$(CONFIG_FDFLUSH) += fdflush.o
-UTILLINUX-$(CONFIG_FDFORMAT) += fdformat.o
-UTILLINUX-$(CONFIG_FDISK) += fdisk.o
-UTILLINUX-$(CONFIG_FREERAMDISK) += freeramdisk.o
-UTILLINUX-$(CONFIG_FSCK_MINIX) += fsck_minix.o
-UTILLINUX-$(CONFIG_GETOPT) += getopt.o
-UTILLINUX-$(CONFIG_HEXDUMP) += hexdump.o
-UTILLINUX-$(CONFIG_HWCLOCK) += hwclock.o
-UTILLINUX-$(CONFIG_LOSETUP) += losetup.o
-UTILLINUX-$(CONFIG_MKFS_MINIX) += mkfs_minix.o
-UTILLINUX-$(CONFIG_MKSWAP) += mkswap.o
-UTILLINUX-$(CONFIG_MORE) += more.o
-UTILLINUX-$(CONFIG_MOUNT) += mount.o
-UTILLINUX-$(CONFIG_NFSMOUNT) += nfsmount.o
-UTILLINUX-$(CONFIG_PIVOT_ROOT) += pivot_root.o
-UTILLINUX-$(CONFIG_RDATE) += rdate.o
-UTILLINUX-$(CONFIG_SWAPONOFF) += swaponoff.o
-UTILLINUX-$(CONFIG_UMOUNT) += umount.o
-
-libraries-y+=$(UTILLINUX_DIR)$(UTILLINUX_AR)
-
-$(UTILLINUX_DIR)$(UTILLINUX_AR): $(patsubst %,$(UTILLINUX_DIR)%, $(UTILLINUX-y))
- $(AR) -ro $@ $(patsubst %,$(UTILLINUX_DIR)%, $(UTILLINUX-y))
-
diff --git a/release/src/router/busybox/util-linux/acpid.c b/release/src/router/busybox/util-linux/acpid.c
new file mode 100644
index 00000000..49ea52d5
--- /dev/null
+++ b/release/src/router/busybox/util-linux/acpid.c
@@ -0,0 +1,167 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * simple ACPI events listener
+ *
+ * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
+
+#include <linux/input.h>
+#ifndef SW_RFKILL_ALL
+# define SW_RFKILL_ALL 3
+#endif
+
+/*
+ * acpid listens to ACPI events coming either in textual form
+ * from /proc/acpi/event (though it is marked deprecated,
+ * it is still widely used and _is_ a standard) or in binary form
+ * from specified evdevs (just use /dev/input/event*).
+ * It parses the event to retrieve ACTION and a possible PARAMETER.
+ * It then spawns /etc/acpi/<ACTION>[/<PARAMETER>] either via run-parts
+ * (if the resulting path is a directory) or directly.
+ * If the resulting path does not exist it logs it via perror
+ * and continues listening.
+ */
+
+static void process_event(const char *event)
+{
+ struct stat st;
+ char *handler = xasprintf("./%s", event);
+ const char *args[] = { "run-parts", handler, NULL };
+
+ // debug info
+ if (option_mask32 & 8) { // -d
+ bb_error_msg("%s", event);
+ }
+
+ // spawn handler
+ // N.B. run-parts would require scripts to have #!/bin/sh
+ // handler is directory? -> use run-parts
+ // handler is file? -> run it directly
+ if (0 == stat(event, &st))
+ spawn((char **)args + (0==(st.st_mode & S_IFDIR)));
+ else
+ bb_simple_perror_msg(event);
+ free(handler);
+}
+
+/*
+ * acpid [-c conf_dir] [-l log_file] [-e proc_event_file] [evdev_event_file...]
+*/
+
+int acpid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int acpid_main(int argc, char **argv)
+{
+ struct pollfd *pfd;
+ int i, nfd;
+ const char *opt_conf = "/etc/acpi";
+ const char *opt_input = "/proc/acpi/event";
+ const char *opt_logfile = "/var/log/acpid.log";
+
+ getopt32(argv, "c:e:l:d"
+ USE_FEATURE_ACPID_COMPAT("g:m:s:S:v"),
+ &opt_conf, &opt_input, &opt_logfile
+ USE_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL, NULL)
+ );
+
+ // daemonize unless -d given
+ if (!(option_mask32 & 8)) { // ! -d
+ bb_daemonize_or_rexec(0, argv);
+ close(2);
+ xopen(opt_logfile, O_WRONLY | O_CREAT | O_TRUNC);
+ }
+
+ argv += optind;
+
+ // goto configuration directory
+ xchdir(opt_conf);
+
+ // prevent zombies
+ signal(SIGCHLD, SIG_IGN);
+
+ // no explicit evdev files given? -> use proc event interface
+ if (!*argv) {
+ // proc_event file is just a "config" :)
+ char *token[4];
+ parser_t *parser = config_open(opt_input);
+
+ // dispatch events
+ while (config_read(parser, token, 4, 4, "\0 ", PARSE_NORMAL)) {
+ char *event = xasprintf("%s/%s", token[1], token[2]);
+ process_event(event);
+ free(event);
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ config_close(parser);
+ return EXIT_SUCCESS;
+ }
+
+ // evdev files given, use evdev interface
+
+ // open event devices
+ pfd = xzalloc(sizeof(*pfd) * (argc - optind));
+ nfd = 0;
+ while (*argv) {
+ pfd[nfd].fd = open_or_warn(*argv++, O_RDONLY | O_NONBLOCK);
+ if (pfd[nfd].fd >= 0)
+ pfd[nfd++].events = POLLIN;
+ }
+
+ // dispatch events
+ while (/* !bb_got_signal && */ poll(pfd, nfd, -1) > 0) {
+ for (i = 0; i < nfd; i++) {
+ const char *event;
+ struct input_event ev;
+
+ if (!(pfd[i].revents & POLLIN))
+ continue;
+
+ if (sizeof(ev) != full_read(pfd[i].fd, &ev, sizeof(ev)))
+ continue;
+//bb_info_msg("%d: %d %d %4d", i, ev.type, ev.code, ev.value);
+
+ // filter out unneeded events
+ if (ev.value != 1)
+ continue;
+
+ event = NULL;
+
+ // N.B. we will conform to /proc/acpi/event
+ // naming convention when assigning event names
+
+ // TODO: do we want other events?
+
+ // power and sleep buttons delivered as keys pressed
+ if (EV_KEY == ev.type) {
+ if (KEY_POWER == ev.code)
+ event = "PWRF/00000080";
+ else if (KEY_SLEEP == ev.code)
+ event = "SLPB/00000080";
+ }
+ // switches
+ else if (EV_SW == ev.type) {
+ if (SW_LID == ev.code)
+ event = "LID/00000080";
+ else if (SW_RFKILL_ALL == ev.code)
+ event = "RFKILL";
+ }
+ // filter out unneeded events
+ if (!event)
+ continue;
+
+ // spawn event handler
+ process_event(event);
+ }
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ for (i = 0; i < nfd; i++)
+ close(pfd[i].fd);
+ free(pfd);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/release/src/router/busybox/util-linux/blkid.c b/release/src/router/busybox/util-linux/blkid.c
new file mode 100644
index 00000000..ec699d16
--- /dev/null
+++ b/release/src/router/busybox/util-linux/blkid.c
@@ -0,0 +1,18 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Print UUIDs on all filesystems
+ *
+ * Copyright (C) 2008 Denys Vlasenko.
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "volume_id.h"
+
+int blkid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int blkid_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
+{
+ display_uuid_cache();
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/dmesg.c b/release/src/router/busybox/util-linux/dmesg.c
index b7d17840..f52026c2 100644
--- a/release/src/router/busybox/util-linux/dmesg.c
+++ b/release/src/router/busybox/util-linux/dmesg.c
@@ -1,99 +1,67 @@
/* vi: set sw=4 ts=4: */
-/* dmesg.c -- Print out the contents of the kernel ring buffer
- * Created: Sat Oct 9 16:19:47 1993
- * Revised: Thu Oct 28 21:52:17 1993 by faith@cs.unc.edu
- * Copyright 1993 Theodore Ts'o (tytso@athena.mit.edu)
- * This program comes with ABSOLUTELY NO WARRANTY.
- * Modifications by Rick Sladkey (jrs@world.std.com)
- * Larger buffersize 3 June 1998 by Nicolai Langfeldt, based on a patch
- * by Peeter Joot. This was also suggested by John Hudson.
- * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
- * - added Native Language Support
+/*
*
- * from util-linux -- adapted for busybox by
- * Erik Andersen <andersen@codepoet.org>. I ripped out Native Language
- * Support, replaced getopt, added some gotos for redundant stuff.
+ * dmesg - display/control kernel ring buffer.
*
- * Audited and cleaned up on 7 March 2003 to reduce size of
- * check error handling by Erik Andersen <andersen@codepoet.org>
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ * Copyright 2006 Bernhard Reutner-Fischer <rep.nop@aon.at>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <errno.h>
#include <sys/klog.h>
+#include "libbb.h"
-#include "busybox.h"
-
-int dmesg_main(int argc, char **argv)
+int dmesg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dmesg_main(int argc UNUSED_PARAM, char **argv)
{
- char *buf
-#ifdef CONFIG_FEATURE_CLEAN_UP
- = NULL
-#endif
- ;
- int bufsize = 8196;
- int i, n;
- int level = 0;
- int lastc;
- int cmd = 3;
+ int len;
+ char *buf;
+ char *size, *level;
+ unsigned flags = getopt32(argv, "cs:n:", &size, &level);
+ enum {
+ OPT_c = 1<<0,
+ OPT_s = 1<<1,
+ OPT_n = 1<<2
+ };
- while ((i = getopt(argc, argv, "cn:s:")) > 0) {
- switch (i) {
- case 'c':
- cmd = 4;
- break;
- case 'n':
- cmd = 8;
- level = bb_xgetlarg(optarg, 10, 0, 10);
- break;
- case 's':
- /* I think a 512k max kernel ring buffer is big enough for
- * anybody, as the default is 16k... Could be wrong though.
- * If so I'm sure I'll hear about it by the enraged masses*/
- bufsize = bb_xgetlarg(optarg, 10, 4096, 512*1024);
- break;
- default:
- bb_show_usage();
- }
+ if (flags & OPT_n) {
+ if (klogctl(8, NULL, xatoul_range(level, 0, 10)))
+ bb_perror_msg_and_die("klogctl");
+ return EXIT_SUCCESS;
}
- if (optind < argc) {
- bb_show_usage();
- }
+ len = (flags & OPT_s) ? xatoul_range(size, 2, INT_MAX) : 16384;
+ buf = xmalloc(len);
+ len = klogctl(3 + (flags & OPT_c), buf, len);
+ if (len < 0)
+ bb_perror_msg_and_die("klogctl");
+ if (len == 0)
+ return EXIT_SUCCESS;
- if (cmd == 8) {
- if (klogctl(cmd, NULL, level) < 0)
- goto die_the_death;
- goto all_done;
- }
+ /* Skip <#> at the start of lines, and make sure we end with a newline. */
- buf = xmalloc(bufsize);
- if ((n = klogctl(cmd, buf, bufsize)) < 0)
- goto die_the_death;
+ if (ENABLE_FEATURE_DMESG_PRETTY) {
+ int last = '\n';
+ int in = 0;
- lastc = '\n';
- for (i = 0; i < n; i++) {
- if (lastc == '\n' && buf[i] == '<') {
- i++;
- while (buf[i] >= '0' && buf[i] <= '9')
- i++;
- if (buf[i] == '>')
- i++;
- }
- lastc = buf[i];
- putchar(lastc);
+ do {
+ if (last == '\n' && buf[in] == '<')
+ in += 3;
+ else {
+ last = buf[in++];
+ bb_putchar(last);
+ }
+ } while (in < len);
+ if (last != '\n')
+ bb_putchar('\n');
+ } else {
+ full_write(STDOUT_FILENO, buf, len);
+ if (buf[len-1] != '\n')
+ bb_putchar('\n');
}
- if (lastc != '\n')
- putchar('\n');
-all_done:
-#ifdef CONFIG_FEATURE_CLEAN_UP
- if (buf) {
- free(buf);
- }
-#endif
+
+ if (ENABLE_FEATURE_CLEAN_UP) free(buf);
+
return EXIT_SUCCESS;
-die_the_death:
- bb_perror_nomsg_and_die();
}
diff --git a/release/src/router/busybox/util-linux/fbset.c b/release/src/router/busybox/util-linux/fbset.c
index f66ebe54..affeab06 100644
--- a/release/src/router/busybox/util-linux/fbset.c
+++ b/release/src/router/busybox/util-linux/fbset.c
@@ -4,43 +4,18 @@
*
* Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 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:
+ * the GPL, and is (c) 1995-1999 by:
* Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdint.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-#define DEFAULTFBDEV "/dev/fb0"
-#define DEFAULTFBMODE "/etc/fb.modes"
+#include "libbb.h"
-static const int OPT_CHANGE = (1 << 0);
-static const int OPT_INFO = (1 << 1);
-static const int OPT_READMODE = (1 << 2);
+#define DEFAULTFBDEV FB_0
+#define DEFAULTFBMODE "/etc/fb.modes"
enum {
CMD_FB = 1,
@@ -52,12 +27,13 @@ enum {
CMD_VSYNC = 7,
CMD_LACED = 8,
CMD_DOUBLE = 9,
-/* CMD_XCOMPAT = 10, */
+/* CMD_XCOMPAT = 10, */
CMD_ALL = 11,
CMD_INFO = 12,
- CMD_CHANGE = 13,
+ CMD_SHOW = 13,
+ CMD_CHANGE = 14,
-#ifdef CONFIG_FEATURE_FBSET_FANCY
+#if ENABLE_FEATURE_FBSET_FANCY
CMD_XRES = 100,
CMD_YRES = 101,
CMD_VXRES = 102,
@@ -81,345 +57,358 @@ enum {
#endif
};
-static unsigned int g_options = 0;
-
/* Stuff stolen from the kernel's fb.h */
-static const int FBIOGET_VSCREENINFO = 0x4600;
-static const int FBIOPUT_VSCREENINFO = 0x4601;
+#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 */
+ 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 xres; /* visible resolution */
uint32_t yres;
- uint32_t xres_virtual; /* virtual resolution */
+ uint32_t xres_virtual; /* virtual resolution */
uint32_t yres_virtual;
- uint32_t xoffset; /* offset from virtual to visible */
- uint32_t yoffset; /* resolution */
+ uint32_t xoffset; /* offset from virtual to visible */
+ uint32_t yoffset; /* resolution */
- uint32_t bits_per_pixel; /* guess what */
- uint32_t grayscale; /* != 0 Graylevels instead of colors */
+ 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 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 */
+ struct fb_bitfield transp; /* transparency */
- uint32_t nonstd; /* != 0 Non standard pixel format */
+ uint32_t nonstd; /* !=0 Non standard pixel format */
- uint32_t activate; /* see FB_ACTIVATE_* */
+ 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 height; /* height of picture in mm */
+ uint32_t width; /* width of picture in mm */
- uint32_t accel_flags; /* acceleration flags (hints) */
+ 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 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_* */
- uint32_t vmode; /* see FB_VMODE_* */
- uint32_t reserved[6]; /* Reserved for future compatibility */
+ 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 */
};
-const static struct cmdoptions_t {
- const char *name;
+static const struct cmdoptions_t {
+ const char name[9];
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}, {
+ /*"12345678" + NUL */
+ { "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 },
+ { "show" , 0, CMD_SHOW },
+ { "s" , 0, CMD_SHOW },
+#if ENABLE_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, 0}
};
-#ifdef CONFIG_FEATURE_FBSET_READMODE
+#if ENABLE_FEATURE_FBSET_READMODE
/* taken from linux/fb.h */
-static const int FB_VMODE_INTERLACED = 1; /* interlaced */
-static const int FB_VMODE_DOUBLE = 2; /* double scan */
-static const int FB_SYNC_HOR_HIGH_ACT = 1; /* horizontal sync high active */
-static const int FB_SYNC_VERT_HIGH_ACT = 2; /* vertical sync high active */
-static const int FB_SYNC_EXT = 4; /* external sync */
-static const int FB_SYNC_COMP_HIGH_ACT = 8; /* composite sync high active */
+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,
+
+#if ENABLE_FEATURE_FBSET_READMODE
+static void ss(uint32_t *x, uint32_t flag, char *buf, const char *what)
+{
+ if (strcmp(buf, what) == 0)
+ *x &= ~flag;
+ else
+ *x |= flag;
+}
+
+static int read_mode_db(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 = bb_xfopen(fn, "r");
- while (!feof(f)) {
- fgets(buf, sizeof(buf), f);
- if ((p = strstr(buf, "mode ")) || (p = strstr(buf, "mode\t"))) {
- p += 5;
- if ((p = strstr(buf, mode))) {
- 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;
-
- 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;
- }
- }
+ char *token[2], *p, *s;
+ parser_t *parser = config_open(fn);
+
+ while (config_read(parser, token, 2, 1, "# \t\r", PARSE_NORMAL)) {
+ if (strcmp(token[0], "mode") != 0 || !token[1])
+ continue;
+ p = strstr(token[1], mode);
+ if (!p)
+ continue;
+ s = p + strlen(mode);
+ //bb_info_msg("CHECK[%s][%s][%d]", mode, p-1, *s);
+ /* exact match? */
+ if (((!*s || isspace(*s)) && '"' != s[-1]) /* end-of-token */
+ || ('"' == *s && '"' == p[-1]) /* ends with " but starts with " too! */
+ ) {
+ //bb_info_msg("FOUND[%s][%s][%s][%d]", token[1], p, mode, isspace(*s));
+ break;
+ }
+ }
+
+ if (!token[0])
+ return 0;
+
+ while (config_read(parser, token, 2, 1, "# \t", PARSE_NORMAL)) {
+ int i;
+
+//bb_info_msg("???[%s][%s]", token[0], token[1]);
+ if (strcmp(token[0], "endmode") == 0) {
+//bb_info_msg("OK[%s]", mode);
+ return 1;
+ }
+ p = token[1];
+ i = index_in_strings(
+ "geometry\0timings\0interlaced\0double\0vsync\0hsync\0csync\0extsync\0",
+ token[0]);
+ switch (i) {
+ case 0:
+ /* 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));
+//bb_info_msg("GEO[%s]", p);
+ break;
+ case 1:
+ 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));
+//bb_info_msg("TIM[%s]", p);
+ break;
+ case 2:
+ case 3: {
+ static const uint32_t syncs[] = {FB_VMODE_INTERLACED, FB_VMODE_DOUBLE};
+ ss(&base->vmode, syncs[i-2], p, "false");
+//bb_info_msg("VMODE[%s]", p);
+ break;
+ }
+ case 4:
+ case 5:
+ case 6: {
+ static const uint32_t syncs[] = {FB_SYNC_VERT_HIGH_ACT, FB_SYNC_HOR_HIGH_ACT, FB_SYNC_COMP_HIGH_ACT};
+ ss(&base->sync, syncs[i-4], p, "low");
+//bb_info_msg("SYNC[%s]", p);
+ break;
+ }
+ case 7:
+ ss(&base->sync, FB_SYNC_EXT, p, "false");
+//bb_info_msg("EXTSYNC[%s]", p);
+ break;
}
}
-#else
- bb_error_msg( "mode reading not compiled in");
-#endif
return 0;
}
+#endif
-static inline void setmode(struct fb_var_screeninfo *base,
+static void setmode(struct fb_var_screeninfo *base,
struct fb_var_screeninfo *set)
{
- if ((int) set->xres > 0)
+ if ((int32_t) set->xres > 0)
base->xres = set->xres;
- if ((int) set->yres > 0)
+ if ((int32_t) set->yres > 0)
base->yres = set->yres;
- if ((int) set->xres_virtual > 0)
+ if ((int32_t) set->xres_virtual > 0)
base->xres_virtual = set->xres_virtual;
- if ((int) set->yres_virtual > 0)
+ if ((int32_t) set->yres_virtual > 0)
base->yres_virtual = set->yres_virtual;
- if ((int) set->bits_per_pixel > 0)
+ if ((int32_t) set->bits_per_pixel > 0)
base->bits_per_pixel = set->bits_per_pixel;
}
-static inline void showmode(struct fb_var_screeninfo *v)
+static 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);
+ 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
+#if ENABLE_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\nendmode\n\n",
- v->xres, v->yres, (int) (vrate + 0.5),
-#ifdef CONFIG_FEATURE_FBSET_FANCY
- drate / 1e6, hrate / 1e3, vrate,
+ "\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),
+#if ENABLE_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);
+ 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
-extern int fbset_main(int argc, char **argv)
-#endif
+int fbset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int fbset_main(int argc, char **argv)
{
+ enum {
+ OPT_CHANGE = (1 << 0),
+ OPT_SHOW = (1 << 1),
+ OPT_READMODE = (1 << 2),
+ OPT_ALL = (1 << 9),
+ };
struct fb_var_screeninfo var, varset;
int fh, i;
- char *fbdev = DEFAULTFBDEV;
- char *modefile = DEFAULTFBMODE;
+ unsigned options = 0;
+
+ const char *fbdev = DEFAULTFBDEV;
+ const char *modefile = DEFAULTFBMODE;
char *thisarg, *mode = NULL;
- memset(&varset, 0xFF, sizeof(varset));
+ 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; i++) {
- if (!strcmp(thisarg, g_cmdoptions[i].name)) {
- 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 = strtoul(argv[1], 0, 0);
- varset.yres = strtoul(argv[2], 0, 0);
- varset.xres_virtual = strtoul(argv[3], 0, 0);
- varset.yres_virtual = strtoul(argv[4], 0, 0);
- varset.bits_per_pixel = strtoul(argv[5], 0, 0);
- break;
- case CMD_TIMING:
- varset.pixclock = strtoul(argv[1], 0, 0);
- varset.left_margin = strtoul(argv[2], 0, 0);
- varset.right_margin = strtoul(argv[3], 0, 0);
- varset.upper_margin = strtoul(argv[4], 0, 0);
- varset.lower_margin = strtoul(argv[5], 0, 0);
- varset.hsync_len = strtoul(argv[6], 0, 0);
- varset.vsync_len = strtoul(argv[7], 0, 0);
- break;
- case CMD_CHANGE:
- g_options |= OPT_CHANGE;
- break;
-#ifdef CONFIG_FEATURE_FBSET_FANCY
- case CMD_XRES:
- varset.xres = strtoul(argv[1], 0, 0);
- break;
- case CMD_YRES:
- varset.yres = strtoul(argv[1], 0, 0);
- break;
- case CMD_DEPTH:
- varset.bits_per_pixel = strtoul(argv[1], 0, 0);
- break;
-#endif
- }
- argc -= g_cmdoptions[i].param_count;
- argv += g_cmdoptions[i].param_count;
+ for (; argc > 0 && (thisarg = *argv) != NULL; argc--, argv++) {
+ if (thisarg[0] == '-') for (i = 0; i < ARRAY_SIZE(g_cmdoptions); i++) {
+ if (strcmp(thisarg + 1, g_cmdoptions[i].name) != 0)
+ continue;
+ if (argc <= 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_ALL:
+ options |= OPT_ALL;
+ break;
+ case CMD_SHOW:
+ options |= OPT_SHOW;
+ 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;
+#if ENABLE_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
}
- }
- if (!g_cmdoptions[i].name) {
- if (argc == 1) {
- mode = *argv;
- g_options |= OPT_READMODE;
- } else {
- bb_show_usage();
+ switch (g_cmdoptions[i].code) {
+ case CMD_FB:
+ case CMD_DB:
+ case CMD_ALL:
+ case CMD_SHOW:
+ break;
+ default:
+ options |= OPT_CHANGE; /* the other commands imply changes */
}
+ argc -= g_cmdoptions[i].param_count;
+ argv += g_cmdoptions[i].param_count;
+ goto contin;
}
+ if (argc != 1)
+ bb_show_usage();
+ mode = *argv;
+ options |= OPT_READMODE;
+ contin: ;
}
- if ((fh = open(fbdev, O_RDONLY)) < 0)
- bb_perror_msg_and_die("fbset(open)");
- if (ioctl(fh, FBIOGET_VSCREENINFO, &var))
- bb_perror_msg_and_die("fbset(ioctl)");
- if (g_options & OPT_READMODE) {
- if (!readmode(&var, modefile, mode)) {
- bb_error_msg("Unknown video mode `%s'", mode);
- return EXIT_FAILURE;
+ fh = xopen(fbdev, O_RDONLY);
+ xioctl(fh, FBIOGET_VSCREENINFO, &var);
+ if (options & OPT_READMODE) {
+#if !ENABLE_FEATURE_FBSET_READMODE
+ bb_show_usage();
+#else
+ if (!read_mode_db(&var, modefile, mode)) {
+ bb_error_msg_and_die("unknown video mode '%s'", mode);
}
+#endif
}
- setmode(&var, &varset);
- if (g_options & OPT_CHANGE)
- if (ioctl(fh, FBIOPUT_VSCREENINFO, &var))
- bb_perror_msg_and_die("fbset(ioctl)");
- showmode(&var);
+ if (options & OPT_CHANGE) {
+ setmode(&var, &varset);
+ if (options & OPT_ALL)
+ var.activate = FB_ACTIVATE_ALL;
+ xioctl(fh, FBIOPUT_VSCREENINFO, &var);
+ }
+ if (options == 0 || options & OPT_SHOW)
+ showmode(&var);
/* Don't close the file, as exiting will take care of that */
/* close(fh); */
diff --git a/release/src/router/busybox/util-linux/fdflush.c b/release/src/router/busybox/util-linux/fdflush.c
deleted file mode 100644
index c3fcf332..00000000
--- a/release/src/router/busybox/util-linux/fdflush.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini fdflush implementation for busybox
- *
- * Copyright (C) 1995, 1996 by Bruce Perens <bruce@perens.com>.
- * Copyright (C) 2003 by Erik Andersen <andersen@codeoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-/* From <linux/fd.h> */
-#define FDFLUSH _IO(2,0x4b)
-
-extern int fdflush_main(int argc, char **argv)
-{
- int fd, result;
-
- if (argc <= 1)
- bb_show_usage();
-
- fd = bb_xopen(argv[1], 0);
-
- result = ioctl(fd, FDFLUSH, 0);
-#ifdef CONFIG_FEATURE_CLEAN_UP
- close(fd);
-#endif
- if (result) {
- bb_perror_nomsg_and_die();
- }
-
- /* Don't bother closing. Exit does
- * that, so we can save a few bytes */
- return EXIT_SUCCESS;
-}
diff --git a/release/src/router/busybox/util-linux/fdformat.c b/release/src/router/busybox/util-linux/fdformat.c
index 5b926467..3831ab44 100644
--- a/release/src/router/busybox/util-linux/fdformat.c
+++ b/release/src/router/busybox/util-linux/fdformat.c
@@ -1,22 +1,11 @@
-/* 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
- *
+/* vi: set sw=4 ts=4: */
+/* fdformat.c - Low-level formats a floppy disk - Werner Almesberger
* 5 July 2003 -- modified for Busybox by Erik Andersen
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
+#include "libbb.h"
/* Stuff extracted from linux/fd.h */
@@ -52,107 +41,91 @@ struct format_descr {
#define FDGETPRM _IOR(2, 0x04, struct floppy_struct)
#define FD_FILL_BYTE 0xF6 /* format fill byte. */
-
-
-static void format_disk(int ctrl, char *name, struct floppy_struct *param)
+int fdformat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int fdformat_main(int argc UNUSED_PARAM, char **argv)
{
- struct format_descr descr;
- int track;
-
- printf("Formatting ... ");
- fflush(stdout);
- if (ioctl(ctrl,FDFMTBEG,NULL) < 0) {
- bb_perror_msg_and_die("FDFMTBEG");
- }
- for (track = 0; track < param->track; track++)
- {
- descr.track = track;
- descr.head = 0;
- if (ioctl(ctrl,FDFMTTRK,(long) &descr) < 0) {
- bb_perror_msg_and_die("FDFMTTRK");
+ int fd, n, cyl, read_bytes, verify;
+ unsigned char *data;
+ struct stat st;
+ struct floppy_struct param;
+ struct format_descr descr;
+
+ opt_complementary = "=1"; /* must have 1 param */
+ verify = !getopt32(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 */
}
- printf("%3d\b\b\b",track);
- fflush(stdout);
- if (param->head == 2) {
- descr.head = 1;
- if (ioctl(ctrl,FDFMTTRK,(long) &descr) < 0) {
- bb_perror_msg_and_die("FDFMTTRK");
- }
+ /* O_RDWR for formatting and verifying */
+ fd = xopen(*argv, O_RDWR);
+
+ /* original message was: "Could not determine current format type" */
+ xioctl(fd, FDGETPRM, &param);
+
+ 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);
+
+ /* n == track */
+ for (n = 0; n < param.track; n++) {
+ descr.head = 0;
+ descr.track = n;
+ xioctl(fd, FDFMTTRK, &descr);
+ printf("%3d\b\b\b", n);
+ if (param.head == 2) {
+ descr.head = 1;
+ xioctl(fd, FDFMTTRK, &descr);
+ }
}
- }
- if (ioctl(ctrl,FDFMTEND,NULL) < 0) {
- bb_perror_msg_and_die("FDFMTEND");
- }
- printf("done\n");
-}
-static void verify_disk(char *name, struct floppy_struct *param)
-{
- unsigned char *data;
- int fd,cyl_size,cyl,count,read_bytes;
-
- cyl_size = param->sect*param->head*512;
- data = xmalloc(cyl_size);
- printf("Verifying ... ");
- fflush(stdout);
- fd = bb_xopen(name,O_RDONLY);
- for (cyl = 0; cyl < param->track; cyl++)
- {
- printf("%3d\b\b\b",cyl);
- fflush(stdout);
- read_bytes = safe_read(fd,data,cyl_size);
- if(read_bytes != cyl_size) {
- if(read_bytes < 0) {
- bb_perror_msg("Read: ");
- }
- bb_error_msg_and_die("Problem reading cylinder %d, "
- "expected %d, read %d", cyl, cyl_size, read_bytes);
+ xioctl(fd, FDFMTEND, NULL);
+ 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");
}
- for (count = 0; count < cyl_size; count++)
- if (data[count] != FD_FILL_BYTE) {
- printf("bad data in cyl %d\nContinuing ... ",cyl);
- fflush(stdout);
- break;
- }
- }
- printf("done\n");
- close(fd);
-}
-int fdformat_main(int argc,char **argv)
-{
- int ctrl;
- int verify;
- struct stat st;
- struct floppy_struct param;
-
- if (argc < 2) {
- bb_show_usage();
- }
- verify != bb_getopt_ulflags(argc, argv, "n");
- argv += optind;
-
- if (stat(*argv,&st) < 0 || access(*argv,W_OK) < 0) {
- bb_perror_msg_and_die(*argv);
- }
- 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 */
- }
-
- ctrl = bb_xopen(*argv,O_WRONLY);
- if (ioctl(ctrl,FDGETPRM,(long) &param) < 0) {
- bb_perror_msg_and_die("Could not determine current format type");
- }
- 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_disk(ctrl, *argv, &param);
- close(ctrl);
-
- if (verify) {
- verify_disk(*argv, &param);
- }
- return EXIT_SUCCESS;
+ 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/release/src/router/busybox/util-linux/fdisk.c b/release/src/router/busybox/util-linux/fdisk.c
index 4fecbbb8..dc61e238 100644
--- a/release/src/router/busybox/util-linux/fdisk.c
+++ b/release/src/router/busybox/util-linux/fdisk.c
@@ -1,165 +1,449 @@
+/* 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)
*
- * This program is free software. You can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation: either version 1 or
- * (at your option) any later version.
- *
- * Vladimir Oleynik <dzo@simtreas.ru> 2001,2002 Busybox port
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
*/
-#define UTIL_LINUX_VERSION "2.12pre"
+#ifndef _LARGEFILE64_SOURCE
+/* For lseek64 */
+#define _LARGEFILE64_SOURCE
+#endif
+#include <assert.h> /* assert */
+#include "libbb.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 DEFAULT_SECTOR_SIZE 512
+#define DEFAULT_SECTOR_SIZE_STR "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
+
+
+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,
+};
-#define PROC_PARTITIONS "/proc/partitions"
-#include <sys/types.h>
-#include <sys/stat.h> /* stat */
-#include <ctype.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <setjmp.h>
-#include <assert.h> /* assert */
-#include <getopt.h>
+/* Used for sector numbers. Today's disk sizes make it necessary */
+typedef unsigned long long ullong;
-#include <endian.h>
-#define u_char unsigned char
-#include <scsi/scsi.h> /* SCSI_IOCTL_GET_IDLUN */
-#undef u_char
+struct hd_geometry {
+ unsigned char heads;
+ unsigned char sectors;
+ unsigned short cylinders;
+ unsigned long start;
+};
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <sys/sysmacros.h> /* major */
+#define HDIO_GETGEO 0x0301 /* get device geometry */
-#include <stdint.h> /* for uint32_t, uint16_t, uint8_t, int16_t, etc */
+static const char msg_building_new_label[] ALIGN1 =
+"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";
-/* Copied from linux/major.h */
-#define FLOPPY_MAJOR 2
+static const char msg_part_already_defined[] ALIGN1 =
+"Partition %d is already defined, delete it before re-adding\n";
-#include <sys/utsname.h>
-#include "busybox.h"
+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 */
+} PACKED;
-#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
+static const char unable_to_open[] ALIGN1 = "can't open '%s'";
+static const char unable_to_read[] ALIGN1 = "can't read from %s";
+static const char unable_to_seek[] ALIGN1 = "can't seek on %s";
-#define DKTYPENAMES
+enum label_type {
+ LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF
+};
-#define _(Text) Text
+#define LABEL_IS_DOS (LABEL_DOS == current_label_type)
-#define BLKRRPART _IO(0x12,95) /* re-read partition table */
-#define BLKGETSIZE _IO(0x12,96) /* return device size */
-#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
-#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
-#define BLKGETSIZE64 _IOR(0x12,114,8) /* 8 = sizeof(u64) */
+#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 { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
+
+static void update_units(void);
+#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 get_geometry(void);
+#if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
+static int get_boot(enum action what);
+#else
+static int get_boot(void);
+#endif
+
+#define PLURAL 0
+#define SINGULAR 1
+
+static unsigned get_start_sect(const struct partition *p);
+static unsigned get_nr_sects(const struct partition *p);
/*
- fdisk.h
-*/
+ * 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 */
+ ullong offset; /* disk sector number */
+ char *sectorbuffer; /* disk sector contents */
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ char changed; /* boolean */
+#endif
+};
-#define DEFAULT_SECTOR_SIZE 512
-#define MAX_SECTOR_SIZE 2048
-#define SECTOR_SIZE 512 /* still used in BSD code */
-#define MAXIMUM_PARTS 60
+/* DOS partition types */
-#define ACTIVE_FLAG 0x80
+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
+};
+
+enum {
+ dev_fd = 3 /* the disk */
+};
+
+/* Globals */
+struct globals {
+ char *line_ptr;
+
+ const char *disk_device;
+ int g_partitions; // = 4; /* maximum partition + 1 */
+ unsigned units_per_sector; // = 1;
+ unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
+ unsigned user_set_sector_size;
+ unsigned sector_offset; // = 1;
+ unsigned g_heads, g_sectors, g_cylinders;
+ smallint /* enum label_type */ current_label_type;
+ smallint display_in_cyl_units; // = 1;
+#if ENABLE_FEATURE_OSF_LABEL
+ smallint possibly_osf_label;
+#endif
+
+ smallint listing; /* no aborts for fdisk -l */
+ smallint dos_compatible_flag; // = 1;
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ //int dos_changed;
+ smallint nowarn; /* no warnings for fdisk -l/-s */
+#endif
+ int ext_index; /* the prime extended partition */
+ unsigned user_cylinders, user_heads, user_sectors;
+ unsigned pt_heads, pt_sectors;
+ unsigned kern_heads, kern_sectors;
+ ullong extended_offset; /* offset of link pointers */
+ ullong total_number_of_sectors;
+
+ jmp_buf listingbuf;
+ char line_buffer[80];
+ char partname_buffer[80];
+ /* 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];
+};
+#define G (*ptr_to_globals)
+#define line_ptr (G.line_ptr )
+#define disk_device (G.disk_device )
+#define g_partitions (G.g_partitions )
+#define units_per_sector (G.units_per_sector )
+#define sector_size (G.sector_size )
+#define user_set_sector_size (G.user_set_sector_size)
+#define sector_offset (G.sector_offset )
+#define g_heads (G.g_heads )
+#define g_sectors (G.g_sectors )
+#define g_cylinders (G.g_cylinders )
+#define current_label_type (G.current_label_type )
+#define display_in_cyl_units (G.display_in_cyl_units)
+#define possibly_osf_label (G.possibly_osf_label )
+#define listing (G.listing )
+#define dos_compatible_flag (G.dos_compatible_flag )
+#define nowarn (G.nowarn )
+#define ext_index (G.ext_index )
+#define user_cylinders (G.user_cylinders )
+#define user_heads (G.user_heads )
+#define user_sectors (G.user_sectors )
+#define pt_heads (G.pt_heads )
+#define pt_sectors (G.pt_sectors )
+#define kern_heads (G.kern_heads )
+#define kern_sectors (G.kern_sectors )
+#define extended_offset (G.extended_offset )
+#define total_number_of_sectors (G.total_number_of_sectors)
+#define listingbuf (G.listingbuf )
+#define line_buffer (G.line_buffer )
+#define partname_buffer (G.partname_buffer)
+#define MBRbuffer (G.MBRbuffer )
+#define ptes (G.ptes )
+#define INIT_G() do { \
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+ sector_size = DEFAULT_SECTOR_SIZE; \
+ sector_offset = 1; \
+ g_partitions = 4; \
+ display_in_cyl_units = 1; \
+ units_per_sector = 1; \
+ dos_compatible_flag = 1; \
+} while (0)
+
+
+/* TODO: move to libbb? */
+static ullong bb_BLKGETSIZE_sectors(int fd)
+{
+ uint64_t v64;
+ unsigned long longsectors;
-#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
+ if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
+ /* Got bytes, convert to 512 byte sectors */
+ return (v64 >> 9);
+ }
+ /* Needs temp of type long */
+ if (ioctl(fd, BLKGETSIZE, &longsectors))
+ longsectors = 0;
+ return longsectors;
+}
-#define SUNOS_SWAP 3
-#define WHOLE_DISK 5
#define IS_EXTENDED(i) \
((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
-#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
-
#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
-#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
-#if defined(__GNUC__) || defined(HAS_LONG_LONG)
-typedef long long ext2_loff_t;
-#else
-typedef long ext2_loff_t;
-#endif
+#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
-/* including <linux/hdreg.h> also fails */
-struct hd_geometry {
- unsigned char heads;
- unsigned char sectors;
- unsigned short cylinders;
- unsigned long start;
-};
+#define pt_offset(b, n) \
+ ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
-#define HDIO_GETGEO 0x0301 /* get device geometry */
+#define sector(s) ((s) & 0x3f)
+#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
-struct systypes {
- const unsigned char *name;
-};
+#define hsc2sector(h,s,c) \
+ (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
-static uint sector_size = DEFAULT_SECTOR_SIZE,
- user_set_sector_size,
- sector_offset = 1;
+#define set_hsc(h,s,c,sector) \
+ do { \
+ s = sector % g_sectors + 1; \
+ sector /= g_sectors; \
+ h = sector % g_heads; \
+ sector /= g_heads; \
+ c = sector & 0xff; \
+ s |= (sector >> 2) & 0xc0; \
+ } while (0)
-/*
- * Raw disk label. For DOS-type partition tables the MBR,
- * with descriptions of the primary partitions.
- */
-static char MBRbuffer[MAX_SECTOR_SIZE];
+static void
+close_dev_fd(void)
+{
+ /* Not really closing, but making sure it is open, and to harmless place */
+ xmove_fd(xopen(bb_dev_null, O_RDONLY), dev_fd);
+}
-#ifdef CONFIG_FEATURE_SUN_LABEL
-static int sun_label; /* looking at sun disklabel */
-#else
-#define sun_label 0
-#endif
-#ifdef CONFIG_FEATURE_SGI_LABEL
-static int sgi_label; /* looking at sgi disklabel */
-#else
-#define sgi_label 0
-#endif
-#ifdef CONFIG_FEATURE_AIX_LABEL
-static int aix_label; /* looking at aix disklabel */
-#else
-#define aix_label 0
-#endif
-#ifdef CONFIG_FEATURE_OSF_LABEL
-static int osf_label; /* looking at OSF/1 disklabel */
-static int possibly_osf_label;
-#else
-#define osf_label 0
-#endif
+#if ENABLE_FEATURE_FDISK_WRITABLE
+/* Read line; return 0 or first printable char */
+static int
+read_line(const char *prompt)
+{
+ int sz;
-#define dos_label (!sun_label && !sgi_label && !aix_label && !osf_label)
+ sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
+ if (sz <= 0)
+ exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */
-static uint heads, sectors, cylinders;
-static void update_units(void);
+ 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 unless buf is supplied
+ * Return partition name - uses static storage
*/
static const char *
-partname(const char *dev, int pno, int lth) {
- static char buffer[80];
+partname(const char *dev, int pno, int lth)
+{
const char *p;
int w, wp;
int bufsiz;
char *bufp;
- bufp = buffer;
- bufsiz = sizeof(buffer);
+ bufp = partname_buffer;
+ bufsiz = sizeof(partname_buffer);
w = strlen(dev);
p = "";
@@ -169,7 +453,7 @@ partname(const char *dev, int pno, int lth) {
/* 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) {
+ if (strcmp(dev + w - 4, "disc") == 0) {
w -= 4;
p = "part";
}
@@ -185,623 +469,125 @@ partname(const char *dev, int pno, int lth) {
return bufp;
}
-struct partition {
- unsigned char boot_ind; /* 0x80 - active */
- unsigned char head; /* starting head */
- unsigned char sector; /* starting sector */
- unsigned char cyl; /* starting cylinder */
- unsigned char sys_ind; /* What partition type */
- unsigned char end_head; /* end head */
- unsigned char end_sector; /* end sector */
- unsigned char end_cyl; /* end cylinder */
- unsigned char start4[4]; /* starting sector counting from 0 */
- unsigned char size4[4]; /* nr of sectors in partition */
-};
-
-enum failure {
- ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
- unable_to_write
-};
-
-enum action {fdisk, require, try_only, create_empty_dos, create_empty_sun};
-
-static const char *disk_device;
-static int fd; /* the disk */
-static int partitions = 4; /* maximum partition + 1 */
-static uint display_in_cyl_units = 1;
-static uint units_per_sector = 1;
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
-static char *line_ptr;
-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 struct systypes *sys);
-static uint read_int(uint low, uint dflt, uint high, uint base, 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
-
-#define hex_val(c) ({ \
- char _c = (c); \
- isdigit(_c) ? _c - '0' : \
- tolower(_c) + 10 - 'a'; \
- })
-
-
-#define LINE_LENGTH 800
-#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) { \
- s = sector % sectors + 1; \
- sector /= sectors; \
- h = sector % heads; \
- sector /= heads; \
- c = sector & 0xff; \
- s |= (sector >> 2) & 0xc0; \
- }
-
-
-static unsigned int get_start_sect(const struct partition *p);
-static unsigned int 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.
- */
-static struct pte {
- struct partition *part_table; /* points into sectorbuffer */
- struct partition *ext_pointer; /* points into sectorbuffer */
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
- char changed; /* boolean */
-#endif
- uint offset; /* disk sector number */
- char *sectorbuffer; /* disk sector contents */
-} ptes[MAXIMUM_PARTS];
-
-
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
+#if ENABLE_FEATURE_FDISK_WRITABLE
static void
-set_all_unchanged(void) {
+set_all_unchanged(void)
+{
int i;
for (i = 0; i < MAXIMUM_PARTS; i++)
ptes[i].changed = 0;
}
-static void
-set_changed(int i) {
+static ALWAYS_INLINE void
+set_changed(int i)
+{
ptes[i].changed = 1;
}
-#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
+#endif /* FEATURE_FDISK_WRITABLE */
-#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_OSF_LABEL)
-static struct partition *
-get_part_table(int i) {
+static ALWAYS_INLINE struct partition *
+get_part_table(int i)
+{
return ptes[i].part_table;
}
-#endif
static const char *
-str_units(int n) { /* n==1: use singular */
+str_units(int n)
+{ /* n==1: use singular */
if (n == 1)
- return display_in_cyl_units ? _("cylinder") : _("sector");
- else
- return display_in_cyl_units ? _("cylinders") : _("sectors");
+ return display_in_cyl_units ? "cylinder" : "sector";
+ return display_in_cyl_units ? "cylinders" : "sectors";
}
static int
-valid_part_table_flag(const unsigned char *b) {
- return (b[510] == 0x55 && b[511] == 0xaa);
+valid_part_table_flag(const char *mbuffer)
+{
+ return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
}
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
-static char line_buffer[LINE_LENGTH];
-
-/* read line; return 0 or first char */
-static int
-read_line(void)
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static ALWAYS_INLINE void
+write_part_table_flag(char *b)
{
- static int got_eof = 0;
-
- fflush (stdout); /* requested by niles@scyld.com */
- line_ptr = line_buffer;
- if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
- if (feof(stdin))
- got_eof++; /* user typed ^D ? */
- if (got_eof >= 3) {
- fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
- exit(1);
- }
- return 0;
- }
- while (*line_ptr && !isgraph(*line_ptr))
- line_ptr++;
- return *line_ptr;
+ b[510] = 0x55;
+ b[511] = 0xaa;
}
static char
-read_char(const char *mesg)
+read_nonempty(const char *mesg)
{
- do {
- fputs(mesg, stdout);
- } while (!read_line());
+ while (!read_line(mesg))
+ continue;
return *line_ptr;
}
static char
-read_chars(const char *mesg)
+read_maybe_empty(const char *mesg)
{
- fputs(mesg, stdout);
- if (!read_line()) {
- *line_ptr = '\n';
- line_ptr[1] = 0;
+ if (!read_line(mesg)) {
+ line_ptr = line_buffer;
+ line_ptr[0] = '\n';
+ line_ptr[1] = '\0';
}
- return *line_ptr;
+ return line_ptr[0];
}
static int
-read_hex(const struct systypes *sys)
+read_hex(const char *const *sys)
{
- int hex;
-
- while (1)
- {
- read_char(_("Hex code (type L to list codes): "));
- if (*line_ptr == 'l' || *line_ptr == 'L')
- list_types(sys);
- else if (isxdigit (*line_ptr))
- {
- hex = 0;
- do
- hex = hex << 4 | hex_val(*line_ptr++);
- while (isxdigit(*line_ptr));
- return hex;
- }
+ 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 /* CONFIG_FEATURE_FDISK_WRITABLE */
-
-#ifdef CONFIG_FEATURE_AIX_LABEL
-/*
- * Copyright (C) Andreas Neuper, Sep 1998.
- * This file may be redistributed under
- * the terms of the GNU Public License.
- */
+#endif /* FEATURE_FDISK_WRITABLE */
-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\tThere is a valid AIX label on this disk.\n"
- "\tUnfortunately Linux cannot handle these\n"
- "\tdisks at the moment. Nevertheless some\n"
- "\tadvice:\n"
- "\t1. fdisk will destroy its contents on write.\n"
- "\t2. Be sure that this disk is NOT a still vital\n"
- "\t part of a volume group. (Otherwise you may\n"
- "\t erase the other disks as well, if unmirrored.)\n"
- "\t3. Before deleting this physical volume be sure\n"
- "\t to remove the disk logically from your AIX\n"
- "\t machine. (Otherwise you become an AIXpert).")
- );
+static void fdisk_fatal(const char *why)
+{
+ if (listing) {
+ close_dev_fd();
+ longjmp(listingbuf, 1);
+ }
+ bb_error_msg_and_die(why, disk_device);
}
static void
-aix_nolabel( void )
+seek_sector(ullong secno)
{
- aixlabel->magic = 0;
- aix_label = 0;
- partitions = 4;
- memset( MBRbuffer, 0, sizeof(MBRbuffer) ); /* avoid fdisk cores */
- return;
+ secno *= sector_size;
+#if ENABLE_FDISK_SUPPORT_LARGE_DISKS
+ if (lseek64(dev_fd, (off64_t)secno, SEEK_SET) == (off64_t) -1)
+ fdisk_fatal(unable_to_seek);
+#else
+ if (secno > MAXINT(off_t)
+ || lseek(dev_fd, (off_t)secno, SEEK_SET) == (off_t) -1
+ ) {
+ fdisk_fatal(unable_to_seek);
+ }
+#endif
}
-static int
-check_aix_label( void )
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static void
+write_sector(ullong secno, const void *buf)
{
- if (aixlabel->magic != AIX_LABEL_MAGIC &&
- aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
- aix_label = 0;
- aix_other_endian = 0;
- return 0;
- }
- aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
- update_units();
- aix_label = 1;
- partitions= 1016;
- aix_volumes = 15;
- aix_info();
- aix_nolabel(); /* %% */
- aix_label = 1; /* %% */
- return 1;
+ seek_sector(secno);
+ xwrite(dev_fd, buf, sector_size);
}
-#endif /* AIX_LABEL */
-
-#ifdef CONFIG_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 acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-
-#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 (__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 */
-
-#ifdef DKTYPENAMES
-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)
-#endif
-
-/*
- * Filesystem type and version.
- * Used to interpret other filesystem-specific
- * per-partition information.
- */
-#define BSD_FS_UNUSED 0 /* unused */
-#define BSD_FS_SWAP 1 /* swap */
-#define BSD_FS_V6 2 /* Sixth Edition */
-#define BSD_FS_V7 3 /* Seventh Edition */
-#define BSD_FS_SYSV 4 /* System V */
-#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
-#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
-#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
-#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
-#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
-#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
-#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
-#define BSD_FS_ISOFS BSD_FS_ISO9660
-#define BSD_FS_BOOT 13 /* partition contains bootstrap */
-#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
-#define BSD_FS_HFS 15 /* Macintosh HFS */
-#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
-#ifdef DKTYPENAMES
-static const struct systypes xbsd_fstypes[] = {
-/* BSD_FS_UNUSED */ {"\x00" "unused"},
-/* BSD_FS_SWAP */ {"\x01" "swap"},
-/* BSD_FS_V6 */ {"\x02" "Version 6"},
-/* BSD_FS_V7 */ {"\x03" "Version 7"},
-/* BSD_FS_SYSV */ {"\x04" "System V"},
-/* BSD_FS_V71K */ {"\x05" "4.1BSD"},
-/* BSD_FS_V8 */ {"\x06" "Eighth Edition"},
-/* BSD_FS_BSDFFS */ {"\x07" "4.2BSD"},
-#ifdef __alpha__
-/* BSD_FS_EXT2 */ {"\x08" "ext2"},
-#else
-/* BSD_FS_MSDOS */ {"\x08" "MS-DOS"},
-#endif
-/* BSD_FS_BSDLFS */ {"\x09" "4.4LFS"},
-/* BSD_FS_OTHER */ {"\x0a" "unknown"},
-/* BSD_FS_HPFS */ {"\x0b" "HPFS"},
-/* BSD_FS_ISO9660 */ {"\x0c" "ISO-9660"},
-/* BSD_FS_BOOT */ {"\x0d" "boot"},
-/* BSD_FS_ADOS */ {"\x0e" "ADOS"},
-/* BSD_FS_HFS */ {"\x0f" "HFS"},
-/* BSD_FS_ADVFS */ {"\x10" "AdvFS"},
- { NULL }
-};
-#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
-
-#endif
-
-/*
- * flags shared by various drives:
- */
-#define BSD_D_REMOVABLE 0x01 /* removable media */
-#define BSD_D_ECC 0x02 /* supports ECC */
-#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
-#define BSD_D_RAMDISK 0x08 /* disk emulator */
-#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
-#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
-
-#endif /* OSF_LABEL */
-
-/*
- * Copyright (C) Andreas Neuper, Sep 1998.
- * This file may be modified and redistributed under
- * the terms of the GNU Public License.
- */
-
-struct device_parameter { /* 48 bytes */
- unsigned char skew;
- unsigned char gap1;
- unsigned char gap2;
- unsigned char sparecyl;
- unsigned short pcylcount;
- unsigned short head_vol0;
- unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
- unsigned char cmd_tag_queue_depth;
- unsigned char unused0;
- unsigned short unused1;
- unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
- unsigned short bytes;
- unsigned short ilfact;
- unsigned int flags; /* controller flags */
- unsigned int datarate;
- unsigned int retries_on_error;
- unsigned int ms_per_word;
- unsigned short xylogics_gap1;
- unsigned short xylogics_syncdelay;
- unsigned short xylogics_readdelay;
- unsigned short xylogics_gap2;
- unsigned short xylogics_readgate;
- unsigned short xylogics_writecont;
-};
-
-#define SGI_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 ENTIRE_DISK SGI_VOLUME
-/*
- * controller flags
- */
-#define SECTOR_SLIP 0x01
-#define SECTOR_FWD 0x02
-#define TRACK_FWD 0x04
-#define TRACK_MULTIVOL 0x08
-#define IGNORE_ERRORS 0x10
-#define RESEEK 0x20
-#define ENABLE_CMDTAGQ 0x40
-
-typedef struct {
- unsigned int magic; /* expect SGI_LABEL_MAGIC */
- unsigned short boot_part; /* active boot partition */
- unsigned short swap_part; /* active swap partition */
- unsigned char boot_file[16]; /* name of the bootfile */
- struct device_parameter devparam; /* 1 * 48 bytes */
- struct volume_directory { /* 15 * 16 bytes */
- unsigned char vol_file_name[8]; /* a character array */
- unsigned int vol_file_start; /* number of logical block */
- unsigned int vol_file_size; /* number of bytes */
- } directory[15];
- struct sgi_partition { /* 16 * 12 bytes */
- unsigned int num_sectors; /* number of blocks */
- unsigned int start_sector; /* 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 ? __swap16(x) \
- : (uint16_t)(x))
-#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) \
- : (uint32_t)(x))
-
-#define sgilabel ((sgi_partition *)MBRbuffer)
-#define sgiparam (sgilabel->devparam)
+#include "fdisk_aix.c"
typedef struct {
unsigned char info[128]; /* Informative text string */
@@ -823,2869 +609,382 @@ typedef struct {
unsigned short ntrks; /* Tracks per cylinder */
unsigned short nsect; /* Sectors per track */
unsigned char spare3[4]; /* Even more magic... */
- struct sun_partition {
+ 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 SUN_LABEL_MAGIC 0xDABE
-#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
#define sunlabel ((sun_partition *)MBRbuffer)
-#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) \
- : (uint16_t)(x))
-#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) \
- : (uint32_t)(x))
-
-#ifdef CONFIG_FEATURE_OSF_LABEL
-/*
- 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()
-*/
-
-#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 u_short xbsd_dkcksum (struct xbsd_disklabel *lp);
-static int xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d,
- int pindex);
-static int xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d);
-static int xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d);
-
-#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
-
-#if defined (__alpha__)
-/* We access this through a u_int64_t * when checksumming */
-static char disklabelbuffer[BSD_BBSIZE] __attribute__((aligned(8)));
-#else
-static char disklabelbuffer[BSD_BBSIZE];
-#endif
-
-static struct xbsd_disklabel xbsd_dlabel;
-
-#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, &xbsd_dlabel) == 0)
- return 0;
- return 1;
-}
-
-static void xbsd_print_disklabel(int);
-
-static int
-btrydev (const char * dev) {
- if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
- return -1;
- printf(_("\nBSD label for device: %s\n"), dev);
- xbsd_print_disklabel (0);
- return 0;
-}
-
-static void
-bmenu (void) {
- puts (_("Command action"));
- puts (_("\td\tdelete a BSD partition"));
- puts (_("\te\tedit drive data"));
- puts (_("\ti\tinstall bootstrap"));
- puts (_("\tl\tlist known filesystem types"));
- puts (_("\tm\tprint this menu"));
- puts (_("\tn\tadd a new BSD partition"));
- puts (_("\tp\tprint BSD partition table"));
- puts (_("\tq\tquit without saving changes"));
- puts (_("\tr\treturn to main menu"));
- puts (_("\ts\tshow complete disklabel"));
- puts (_("\tt\tchange a partition's filesystem id"));
- puts (_("\tu\tchange units (cylinders/sectors)"));
- puts (_("\tw\twrite disklabel to disk"));
-#if !defined (__alpha__)
- puts (_("\tx\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
-bselect (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) {
- fprintf (stderr, _("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, &xbsd_dlabel) == 0)
- if (xbsd_create_disklabel () == 0)
- return;
- break;
- }
- }
-
- if (t == 4) {
- printf (_("There is no *BSD partition on %s.\n"), disk_device);
- return;
- }
-
-#elif defined (__alpha__)
-
- if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
- if (xbsd_create_disklabel () == 0)
- exit ( EXIT_SUCCESS );
-
-#endif
-
- while (1) {
- putchar ('\n');
- switch (tolower (read_char (_("BSD disklabel command (m for help): ")))) {
- case 'd':
- xbsd_delete_part ();
- break;
- case 'e':
- xbsd_edit_disklabel ();
- break;
- case 'i':
- xbsd_write_bootstrap ();
- break;
- case 'l':
- xbsd_list_types ();
- break;
- case 'n':
- xbsd_new_part ();
- break;
- case 'p':
- xbsd_print_disklabel (0);
- break;
- case 'q':
- close (fd);
- exit ( EXIT_SUCCESS );
- case '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:
- bmenu ();
- break;
- }
- }
-}
+STATIC_OSF void bsd_select(void);
+STATIC_OSF void xbsd_print_disklabel(int);
+#include "fdisk_osf.c"
-static void
-xbsd_delete_part (void)
+#if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
+static uint16_t
+fdisk_swap16(uint16_t x)
{
- 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--;
+ return (x << 8) | (x >> 8);
}
-static void
-xbsd_new_part (void)
+static uint32_t
+fdisk_swap32(uint32_t x)
{
- uint 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"));
- printf("\n");
- /* 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].name);
- 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;
- }
- printf("\n");
- }
- }
-}
-
-static void
-xbsd_write_disklabel (void) {
-#if defined (__alpha__)
- printf (_("Writing disklabel to %s.\n"), disk_device);
- xbsd_writelabel (NULL, &xbsd_dlabel);
-#else
- printf (_("Writing disklabel to %s.\n"),
- partname(disk_device, xbsd_part_index+1, 0));
- xbsd_writelabel (xbsd_part, &xbsd_dlabel);
-#endif
- reread_partition_table(0); /* no exit yet */
-}
-
-static int
-xbsd_create_disklabel (void) {
- char c;
-
-#if defined (__alpha__)
- fprintf (stderr, _("%s contains no disklabel.\n"), disk_device);
-#else
- fprintf (stderr, _("%s contains no disklabel.\n"),
- partname(disk_device, xbsd_part_index+1, 0));
-#endif
-
- while (1) {
- c = read_char (_("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, &xbsd_dlabel, 0
-#else
- xbsd_part, &xbsd_dlabel, xbsd_part_index
-#endif
- ) == 1) {
- xbsd_print_disklabel (1);
- return 1;
- } else
- return 0;
- } else if (c == 'n')
- return 0;
- }
-}
-
-static int
-edit_int (int def, char *mesg)
-{
- do {
- fputs (mesg, stdout);
- printf (" (%d): ", def);
- if (!read_line ())
- return def;
- }
- while (!isdigit (*line_ptr));
- return atoi (line_ptr);
-}
-
-static void
-xbsd_edit_disklabel (void)
-{
- struct xbsd_disklabel *d;
-
- d = &xbsd_dlabel;
-
-#if defined (__alpha__) || defined (__ia64__)
- d -> d_secsize = (u_long) edit_int ((u_long) d -> d_secsize ,_("bytes/sector"));
- d -> d_nsectors = (u_long) edit_int ((u_long) d -> d_nsectors ,_("sectors/track"));
- d -> d_ntracks = (u_long) edit_int ((u_long) d -> d_ntracks ,_("tracks/cylinder"));
- d -> d_ncylinders = (u_long) edit_int ((u_long) d -> d_ncylinders ,_("cylinders"));
-#endif
-
- /* d -> d_secpercyl can be != d -> d_nsectors * d -> d_ntracks */
- while (1)
- {
- d -> d_secpercyl = (u_long) edit_int ((u_long) d -> d_nsectors * d -> d_ntracks,
- _("sectors/cylinder"));
- if (d -> d_secpercyl <= d -> d_nsectors * d -> d_ntracks)
- break;
-
- printf (_("Must be <= sectors/track * tracks/cylinder (default).\n"));
- }
- d -> d_rpm = (u_short) edit_int ((u_short) d -> d_rpm ,_("rpm"));
- d -> d_interleave = (u_short) edit_int ((u_short) d -> d_interleave,_("interleave"));
- d -> d_trackskew = (u_short) edit_int ((u_short) d -> d_trackskew ,_("trackskew"));
- d -> d_cylskew = (u_short) edit_int ((u_short) d -> d_cylskew ,_("cylinderskew"));
- d -> d_headswitch = (u_long) edit_int ((u_long) d -> d_headswitch ,_("headswitch"));
- d -> d_trkseek = (u_long) edit_int ((u_long) d -> d_trkseek ,_("track-to-track seek"));
-
- d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
-}
-
-static int
-xbsd_get_bootstrap (char *path, void *ptr, int size)
-{
- int fdb;
-
- if ((fdb = open (path, O_RDONLY)) < 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 (_("\nSyncing disks.\n"));
- sync ();
- sleep (4);
-}
-
-static void
-xbsd_write_bootstrap (void)
-{
- char *bootdir = BSD_LINUX_BOOTDIR;
- char path[MAXPATHLEN];
- char *dkbasename;
- struct xbsd_disklabel dl;
- char *d, *p, *e;
- int sector;
-
- if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
- dkbasename = "sd";
- else
- dkbasename = "wd";
-
- printf (_("Bootstrap: %sboot -> boot%s (%s): "),
- dkbasename, dkbasename, dkbasename);
- if (read_line ()) {
- line_ptr[strlen (line_ptr)-1] = '\0';
- dkbasename = line_ptr;
- }
- 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];
- bcopy (d, &dl, sizeof (struct xbsd_disklabel));
-
- /* The disklabel will be overwritten by 0's from bootxx anyway */
- bzero (d, 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) {
- fprintf (stderr, _("Bootstrap overlaps with disk label!\n"));
- exit ( EXIT_FAILURE );
- }
-
- bcopy (&dl, d, 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, (ext2_loff_t) 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[256];
- char l;
-
- snprintf (prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
- do
- l = tolower (read_char (prompt));
- while (l < 'a' || l > 'a' + max - 1);
- return l - 'a';
-}
-
-static int
-xbsd_check_new_partition (int *i) {
-
- /* 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) {
- fprintf (stderr, _("The maximum number of partitions "
- "has been created\n"));
- return 0;
- }
- }
-
- *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
-
- if (*i >= xbsd_dlabel.d_npartitions)
- xbsd_dlabel.d_npartitions = (*i) + 1;
-
- if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
- fprintf (stderr, _("This partition already exists.\n"));
- return 0;
- }
-
- return 1;
-}
-
-static void
-xbsd_list_types (void) {
- list_types (xbsd_fstypes);
-}
-
-static u_short
-xbsd_dkcksum (struct xbsd_disklabel *lp) {
- u_short *start, *end;
- u_short sum = 0;
-
- start = (u_short *) lp;
- end = (u_short *) &lp->d_partitions[lp->d_npartitions];
- while (start < end)
- sum ^= *start++;
- return sum;
-}
-
-static int
-xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex) {
- struct xbsd_partition *pp;
-
- get_geometry ();
- bzero (d, sizeof (struct xbsd_disklabel));
-
- d -> d_magic = BSD_DISKMAGIC;
-
- if (strncmp (disk_device, "/dev/sd", 7) == 0)
- d -> d_type = BSD_DTYPE_SCSI;
- else
- d -> d_type = BSD_DTYPE_ST506;
-
-#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
- d -> d_subtype = BSD_DSTYPE_INDOSPART & pindex;
-#endif
-
-#if !defined (__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
- the NetBSD partition */
- pp -> p_offset = get_start_sect(p);
- pp -> p_size = get_nr_sects(p);
- pp -> p_fstype = BSD_FS_UNUSED;
- pp = &d -> d_partitions[3]; /* Partition D should be
- the whole disk */
- pp -> p_offset = 0;
- pp -> p_size = d -> d_secperunit;
- pp -> p_fstype = BSD_FS_UNUSED;
-#elif defined (__alpha__)
- d -> d_npartitions = 3;
- pp = &d -> d_partitions[2]; /* Partition C should be
- the whole disk */
- pp -> p_offset = 0;
- pp -> p_size = d -> d_secperunit;
- pp -> p_fstype = BSD_FS_UNUSED;
-#endif
-
- return 1;
-}
-
-/*
- * 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;
-
- /* p is used only to get the starting sector */
-#if !defined (__alpha__)
- sector = (p ? get_start_sect(p) : 0);
-#elif defined (__alpha__)
- sector = 0;
-#endif
-
- if (lseek (fd, (ext2_loff_t) sector * SECTOR_SIZE, SEEK_SET) == -1)
- fdisk_fatal (unable_to_seek);
- if (BSD_BBSIZE != read (fd, disklabelbuffer, BSD_BBSIZE))
- fdisk_fatal (unable_to_read);
-
- bcopy (&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
- d, 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)
- fprintf (stderr, _("Warning: too many partitions "
- "(%d, maximum is %d).\n"),
- d -> d_npartitions, BSD_MAXPARTITIONS);
- return 1;
-}
-
-static int
-xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
-{
- 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.
- */
- bcopy (d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
- sizeof (struct xbsd_disklabel));
-
-#if defined (__alpha__) && BSD_LABELSECTOR == 0
- alpha_bootblock_checksum (disklabelbuffer);
- if (lseek (fd, (ext2_loff_t) 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, (ext2_loff_t) 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__)
-
-#if !defined(__GLIBC__)
-typedef unsigned long long u_int64_t;
-#endif
-
-static void
-alpha_bootblock_checksum (char *boot)
-{
- u_int64_t *dp, sum;
- int i;
-
- dp = (u_int64_t *)boot;
- sum = 0;
- for (i = 0; i < 63; i++)
- sum += dp[i];
- dp[63] = sum;
-}
-#endif /* __alpha__ */
-
-#endif /* OSF_LABEL */
-
-#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
-static inline unsigned short
-__swap16(unsigned short x) {
- return (((uint16_t)(x) & 0xFF) << 8) | (((uint16_t)(x) & 0xFF00) >> 8);
-}
-
-static inline uint32_t
-__swap32(uint32_t x) {
- return (((x & 0xFF) << 24) |
- ((x & 0xFF00) << 8) |
- ((x & 0xFF0000) >> 8) |
- ((x & 0xFF000000) >> 24));
-}
-#endif
-
-#ifdef CONFIG_FEATURE_SGI_LABEL
-/*
- *
- * 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 = 0;
- for ( ; 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 struct systypes 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" },
-/* 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 void
-sgi_nolabel(void) {
- sgilabel->magic = 0;
- sgi_label = 0;
- partitions = 4;
-}
-
-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;
-}
-
-static int
-check_sgi_label(void) {
- if (sizeof(sgilabel) > 512) {
- fprintf(stderr,
- _("According to MIPS Computer Systems, Inc the "
- "Label must not contain more than 512 bytes\n"));
- exit(1);
- }
-
- if (sgilabel->magic != SGI_LABEL_MAGIC &&
- sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
- sgi_label = 0;
- sgi_other_endian = 0;
- 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))) {
- fprintf(stderr,
- _("Detected sgi disklabel with wrong checksum.\n"));
- }
- update_units();
- sgi_label = 1;
- 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;
- int kpi = 0; /* kernel partition ID */
-
- w = strlen(disk_device);
-
- if(xtra) {
- printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
- "%d cylinders, %d physical cylinders\n"
- "%d extra sects/cyl, interleave %d:1\n"
- "%s\n"
- "Units = %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 );
- }
- printf(_("----- partitions -----\n"
- "Pt# %*s Info Start End Sectors Id System\n"),
- w + 1, _("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+2),
-/* 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);
- char*name = sgilabel->directory[i].vol_file_name;
-
- printf(_("%2d: %-10s sector%5u size%8u\n"),
- i, 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;
- } else {
- if (strlen(aFile) > 16) {
- printf(_("\n\tName of Bootfile too long: "
- "16 bytes maximum.\n"));
- return 0;
- } else {
- if (aFile[0] != '/') {
- printf(_("\n\tBootfile must have a "
- "fully qualified pathname.\n"));
- return 0;
- }
- }
- }
- if (strncmp(aFile, sgilabel->boot_file, 16)) {
- printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
- "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
- /* filename is correct and did change */
- return 1;
- }
- return 0; /* filename did not change */
-}
-
-static const char *
-sgi_get_bootfile(void) {
- return 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(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(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, (long long)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) == 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]) == 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]) == ENTIRE_DISK) continue;
- if (start > sgi_get_start_sector(Index[i])) {
- if (verbose)
- printf(_("The Partition %d and %d overlap by %d sectors.\n"),
- Index[i-1]+1, Index[i]+1,
- start - sgi_get_start_sector(Index[i]));
- if (gap > 0) gap = -gap;
- if (gap == 0) gap = -1;
- }
- if (start < sgi_get_start_sector(Index[i])) {
- if (verbose)
- printf(_("Unused gap of %8u sectors - sectors %8u-%u\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-%u\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 != ENTIRE_DISK ) && (sys != SGI_VOLHDR))
- && (sgi_get_start_sector(i)<1) )
- {
- read_chars(
- _("It is highly recommended that the partition at offset 0\n"
- "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
- "retrieve from its directory standalone tools like sash and fx.\n"
- "Only the \"SGI volume\" entire disk section may violate this.\n"
- "Type YES if you are sure about tagging this partition differently.\n"));
- if (strcmp (line_ptr, _("YES\n")))
- return;
- }
- sgilabel->partitions[i].id = 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(_("Do You know, You got a partition overlap on the disk?\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 );
-}
-
+ 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
-sgi_add_partition( int n, int sys )
+store4_little_endian(unsigned char *cp, unsigned val)
{
- 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(_("Partition %d is already defined. Delete "
- "it before re-adding it.\n"), n + 1);
- return;
- }
- if( (sgi_entire() == -1) && (sys != SGI_VOLUME) ) {
- printf(_("Attempting to generate entire disk entry automatically.\n"));
- sgi_set_entire();
- sgi_set_volhdr();
- }
- if( (sgi_gaps() == 0) && (sys != SGI_VOLUME) ) {
- printf(_("The entire disk is already covered with partitions.\n"));
- return;
- }
- if(sgi_gaps() < 0) {
- printf(_("You got a partition overlap on the disk. Fix it first!\n"));
- return;
- }
- snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
- for(;;) {
- if(sys == SGI_VOLUME) {
- last = sgi_get_lastblock();
- first = read_int(0, 0, last-1, 0, mesg);
- if( first != 0 ) {
- printf(_("It is highly recommended that eleventh partition\n"
- "covers the entire disk and is of type `SGI volume'\n"));
- }
- } else {
- first = freelist[0].first;
- last = freelist[0].last;
- first = read_int(scround(first), scround(first), scround(last)-1,
- 0, mesg);
- }
- if (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 ) {
- printf(_("You will get a partition overlap on the disk. "
- "Fix it first!\n"));
- } else
- break;
- }
- 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 );
+ cp[0] = val;
+ cp[1] = val >> 8;
+ cp[2] = val >> 16;
+ cp[3] = val >> 24;
}
+#endif /* FEATURE_FDISK_WRITABLE */
-#ifdef CONFIG_FEATURE_FDISK_ADVANCED
-static void
-create_sgilabel(void)
+static unsigned
+read4_little_endian(const unsigned char *cp)
{
- 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 */
-
- fprintf( stderr,
- _("Building a new SGI disklabel. Changes will remain in memory only,\n"
- "until you decide to write them. After that, of course, the previous\n"
- "content will be unrecoverably lost.\n\n"));
-
- 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;
- fprintf(stderr,
- _("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));
- sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
- sgilabel->boot_part = SGI_SSWAP16(0);
- sgilabel->swap_part = SGI_SSWAP16(1);
-
- /* sizeof(sgilabel->boot_file) = 16 > 6 */
- memset(sgilabel->boot_file, 0, 16);
- strcpy(sgilabel->boot_file, "/unix");
-
- 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);
- sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
- /* tracks/cylinder (heads) */
- sgilabel->devparam.cmd_tag_queue_depth = (0);
- sgilabel->devparam.unused0 = (0);
- sgilabel->devparam.unused1 = SGI_SSWAP16(0);
- sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
- /* sectors/track */
- 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_partition)*16 );
- sgi_label = 1;
- 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);
- }
- }
+ return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
}
+#if ENABLE_FEATURE_FDISK_WRITABLE
static void
-sgi_set_xcyl(void)
-{
- /* do nothing in the beginning */
-}
-#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
-
-/* _____________________________________________________________
- */
-
-static sgiinfo *
-fill_sgiinfo(void)
+set_start_sect(struct partition *p, unsigned start_sect)
{
- sgiinfo *info = calloc(1, 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( info->scsi_string, "IBM OEM 0662S12 3 30" );
- strcpy( info->serial, "0000" );
- info->check1816 = SGI_SSWAP16(18*256 +16 );
- strcpy( info->installer, "Sfx version 5.3, Oct 18, 1994" );
- return info;
-}
-#endif /* SGI_LABEL */
-
-
-#ifdef CONFIG_FEATURE_SUN_LABEL
-/*
- * 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 struct systypes sun_sys_types[] = {
-/* 0 */ {"\x00" "Empty" },
-/* 1 */ {"\x01" "Boot" },
-/* 2 */ {"\x02" "SunOS root" },
-/* SUNOS_SWAP */ {"\x03" "SunOS swap" },
-/* 4 */ {"\x04" "SunOS usr" },
-/* WHOLE_DISK */ {"\x05" "Whole disk" },
-/* 6 */ {"\x06" "SunOS stand" },
-/* 7 */ {"\x07" "SunOS var" },
-/* 8 */ {"\x08" "SunOS home" },
-/* LINUX_SWAP */ {"\x82" "Linux swap" },
-/* LINUX_NATIVE */ {"\x83" "Linux native" },
-/* 0x8e */ {"\x8e" "Linux LVM" },
-/* New (2.2.x) raid partition with autodetect using persistent superblock */
-/* 0xfd */ {"\xfd" "Linux raid autodetect" },
- { 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 void
-sun_nolabel(void) {
- sun_label = 0;
- sunlabel->magic = 0;
- partitions = 4;
-}
-
-static int
-check_sun_label(void) {
- unsigned short *ush;
- int csum;
-
- if (sunlabel->magic != SUN_LABEL_MAGIC &&
- sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
- sun_label = 0;
- 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) {
- fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
- "Probably you'll have to set all the values,\n"
- "e.g. heads, sectors, cylinders and partitions\n"
- "or force a fresh label (s command in main menu)\n"));
- } else {
- heads = SUN_SSWAP16(sunlabel->ntrks);
- cylinders = SUN_SSWAP16(sunlabel->ncyl);
- sectors = SUN_SSWAP16(sunlabel->nsect);
- }
- update_units();
- sun_label = 1;
- 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)) {
- sprintf(buffer,
- "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
-#if 0
- ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33,
-#else
- /* This is very wrong (works only if you have one HBA),
- but I haven't found a way how to get hostno
- from the current kernel */
- 0,
-#endif
- (id[0]>>16)&0xff,
- id[0]&0xff,
- (id[0]>>8)&0xff);
- pfd = fopen("/proc/scsi/scsi","r");
- if (pfd) {
- while (fgets(buffer2,2048,pfd)) {
- if (!strcmp(buffer, buffer2)) {
- if (fgets(buffer2,2048,pfd)) {
- q = strstr(buffer2,"Vendor: ");
- if (q) {
- q += 8;
- vendor = q;
- q = strstr(q," ");
- *q++ = 0; /* truncate vendor name */
- q = strstr(q,"Model: ");
- if (q) {
- *q = 0;
- q += 7;
- model = q;
- q = strstr(q," Rev: ");
- if (q) {
- *q = 0;
- for (i = 0; i < SIZE(sun_drives); i++) {
- if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
- continue;
- if (!strstr(model, sun_drives[i].model))
- continue;
- printf(_("Autoconfigure found a %s%s%s\n"),sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model);
- p = sun_drives + i;
- break;
- }
- }
- }
- }
- }
- break;
- }
- }
- fclose(pfd);
- }
- }
-#endif
- return p;
-}
-
-static void create_sunlabel(void)
-{
- struct hd_geometry geometry;
- unsigned int ndiv;
- int i;
- unsigned char c;
- const struct sun_predefined_drives *p = NULL;
-
- fprintf(stderr,
- _("Building a new sun disklabel. Changes will remain in memory only,\n"
- "until you decide to write them. After that, of course, the previous\n"
- "content won't be recoverable.\n\n"));
-#if BYTE_ORDER == LITTLE_ENDIAN
- sun_other_endian = 1;
-#else
- sun_other_endian = 0;
-#endif
- 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);
- }
- for (;;) {
- c = read_char(_("Select type (? for auto, 0 for custom): "));
- if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
- p = sun_drives + c - 'a';
- break;
- } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
- p = sun_drives + c - 'A';
- break;
- } else if (c == '0') {
- break;
- } else if (c == '?' && scsi_disk) {
- p = sun_autoconfigure_scsi();
- if (!p)
- printf(_("Autoconfigure failed.\n"));
- else
- break;
- }
- }
- }
- if (!p || floppy) {
- 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(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, 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 != 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(_("Partition %d is already defined. Delete "
- "it before re-adding it.\n"), n + 1);
- return;
- }
-
- fetch_sun(starts,lens,&start,&stop);
- if (stop <= start) {
- if (n == 2)
- whole_disk = 1;
- else {
- printf(_("Other partitions already cover the whole disk.\nDelete "
- "some/shrink them before retry.\n"));
- return;
- }
- }
- snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
- for (;;) {
- if (whole_disk)
- first = read_int(0, 0, 0, 0, mesg);
- else
- first = read_int(scround(start), scround(stop)+1,
- scround(stop), 0, mesg);
- if (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, but your value\n"
- "%d %s covers some other partition. Your entry has been changed\n"
- "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 = 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 == 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_chars(
- _("It is highly recommended that the partition at offset 0\n"
- "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
- "there may destroy your partition table and bootblock.\n"
- "Type YES if you're very sure you would like that partition\n"
- "tagged with 82 (Linux swap): "));
- if (strcmp (line_ptr, _("YES\n")))
- return;
- }
- switch (sys) {
- case SUNOS_SWAP:
- case LINUX_SWAP:
- /* swaps are not mountable by default */
- sunlabel->infos[i].flags |= 0x01;
- break;
- default:
- /* assume other types are mountable;
- user can change it anyway */
- sunlabel->infos[i].flags &= ~0x01;
- break;
- }
- sunlabel->infos[i].id = sys;
-}
-
-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",
-/* device */ partname(disk_device, i+1, w),
-/* flags */ (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ',
- (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
-/* start */ (long) scround(start),
-/* end */ (long) scround(start+len),
-/* odd flag on end */ (long) len / 2, len & 1 ? '+' : ' ',
-/* type id */ sunlabel->infos[i].id,
-/* type name */ partition_type(sunlabel->infos[i].id));
- }
- }
-}
-
-#ifdef CONFIG_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 /* CONFIG_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 */
-
-/* DOS partition types */
-
-static const struct systypes 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 Win95 FAT32 (LBA)"},
- {"\x1e" "Hidden Win95 FAT16 (LBA)"},
- {"\x3c" "PartitionMagic 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" "IBM 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 */
-#ifdef CONFIG_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
- { 0 }
-};
-
-
-
-/* A valid partition table sector ends in 0x55 0xaa */
-static unsigned int
-part_table_flag(const char *b) {
- return ((uint) b[510]) + (((uint) b[511]) << 8);
-}
-
-
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
-static void
-write_part_table_flag(char *b) {
- b[510] = 0x55;
- b[511] = 0xaa;
-}
-
-/* start_sect and nr_sects are stored little endian on all machines */
-/* moreover, they are not aligned correctly */
-static void
-store4_little_endian(unsigned char *cp, unsigned int val) {
- cp[0] = (val & 0xff);
- cp[1] = ((val >> 8) & 0xff);
- cp[2] = ((val >> 16) & 0xff);
- cp[3] = ((val >> 24) & 0xff);
-}
-#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
-
-static unsigned int
-read4_little_endian(const unsigned char *cp) {
- return (uint)(cp[0]) + ((uint)(cp[1]) << 8)
- + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24);
-}
-
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
-static void
-set_start_sect(struct partition *p, unsigned int start_sect) {
store4_little_endian(p->start4, start_sect);
}
#endif
-static unsigned int
-get_start_sect(const struct partition *p) {
+static unsigned
+get_start_sect(const struct partition *p)
+{
return read4_little_endian(p->start4);
}
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
+#if ENABLE_FEATURE_FDISK_WRITABLE
static void
-set_nr_sects(struct partition *p, unsigned int nr_sects) {
+set_nr_sects(struct partition *p, unsigned nr_sects)
+{
store4_little_endian(p->size4, nr_sects);
}
#endif
-static unsigned int
-get_nr_sects(const struct partition *p) {
+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 */
- listing, /* no aborts for fdisk -l */
- dos_compatible_flag = ~0;
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
-static int dos_changed;
-static int nowarn; /* no warnings for fdisk -l/-s */
-#endif
-
-
-
-static uint user_cylinders, user_heads, user_sectors;
-static uint pt_heads, pt_sectors;
-static uint kern_heads, kern_sectors;
-
-static uint extended_offset; /* offset of link pointers */
-
-static unsigned long long total_number_of_sectors;
-
-
-static jmp_buf listingbuf;
-
-static void fdisk_fatal(enum failure why) {
- const char *message;
-
- if (listing) {
- close(fd);
- longjmp(listingbuf, 1);
- }
-
- switch (why) {
- case unable_to_open:
- message = "Unable to open %s\n";
- break;
- case unable_to_read:
- message = "Unable to read %s\n";
- break;
- case unable_to_seek:
- message = "Unable to seek on %s\n";
- break;
- case unable_to_write:
- message = "Unable to write %s\n";
- break;
- case ioctl_error:
- message = "BLKGETSIZE ioctl failed on %s\n";
- break;
- default:
- message = "Fatal error\n";
- }
-
- fputc('\n', stderr);
- fprintf(stderr, message, disk_device);
- exit(1);
-}
-
-static void
-seek_sector(uint secno) {
- ext2_loff_t offset = (ext2_loff_t) secno * sector_size;
- if (lseek(fd, offset, SEEK_SET) == (ext2_loff_t) -1)
- fdisk_fatal(unable_to_seek);
-}
-
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
-static void
-write_sector(uint 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, uint offset) {
-
+read_pte(struct pte *pe, ullong offset)
+{
pe->offset = offset;
- pe->sectorbuffer = (char *) xmalloc(sector_size);
+ pe->sectorbuffer = xzalloc(sector_size);
seek_sector(offset);
- if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
+ /* xread would make us abort - bad for fdisk -l */
+ if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
fdisk_fatal(unable_to_read);
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
+#if ENABLE_FEATURE_FDISK_WRITABLE
pe->changed = 0;
#endif
pe->part_table = pe->ext_pointer = NULL;
}
-static unsigned int
-get_partition_start(const struct pte *pe) {
+static unsigned
+get_partition_start(const struct pte *pe)
+{
return pe->offset + get_start_sect(pe->part_table);
}
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
+#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".
*/
+#ifdef UNUSED
static int
-is_dos_partition(int t) {
+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);
}
+#endif
static void
-menu(void) {
-#ifdef CONFIG_FEATURE_SUN_LABEL
- if (sun_label) {
- puts(_("Command action"));
- puts(_("\ta\ttoggle a read only flag")); /* sun */
- puts(_("\tb\tedit bsd disklabel"));
- puts(_("\tc\ttoggle the mountable flag")); /* sun */
- puts(_("\td\tdelete a partition"));
- puts(_("\tl\tlist known partition types"));
- puts(_("\tm\tprint this menu"));
- puts(_("\tn\tadd a new partition"));
- puts(_("\to\tcreate a new empty DOS partition table"));
- puts(_("\tp\tprint the partition table"));
- puts(_("\tq\tquit without saving changes"));
- puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
- puts(_("\tt\tchange a partition's system id"));
- puts(_("\tu\tchange display/entry units"));
- puts(_("\tv\tverify the partition table"));
- puts(_("\tw\twrite table to disk and exit"));
-#ifdef CONFIG_FEATURE_FDISK_ADVANCED
- puts(_("\tx\textra functionality (experts only)"));
-#endif
- } else
-#endif
-#ifdef CONFIG_FEATURE_SGI_LABEL
- if (sgi_label) {
- puts(_("Command action"));
- puts(_("\ta\tselect bootable partition")); /* sgi flavour */
- puts(_("\tb\tedit bootfile entry")); /* sgi */
- puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
- puts(_("\td\tdelete a partition"));
- puts(_("\tl\tlist known partition types"));
- puts(_("\tm\tprint this menu"));
- puts(_("\tn\tadd a new partition"));
- puts(_("\to\tcreate a new empty DOS partition table"));
- puts(_("\tp\tprint the partition table"));
- puts(_("\tq\tquit without saving changes"));
- puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
- puts(_("\tt\tchange a partition's system id"));
- puts(_("\tu\tchange display/entry units"));
- puts(_("\tv\tverify the partition table"));
- puts(_("\tw\twrite table to disk and exit"));
- } else
-#endif
-#ifdef CONFIG_FEATURE_AIX_LABEL
- if (aix_label) {
- puts(_("Command action"));
- puts(_("\tm\tprint this menu"));
- puts(_("\to\tcreate a new empty DOS partition table"));
- puts(_("\tq\tquit without saving changes"));
- puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
- } else
-#endif
- {
- puts(_("Command action"));
- puts(_("\ta\ttoggle a bootable flag"));
- puts(_("\tb\tedit bsd disklabel"));
- puts(_("\tc\ttoggle the dos compatibility flag"));
- puts(_("\td\tdelete a partition"));
- puts(_("\tl\tlist known partition types"));
- puts(_("\tm\tprint this menu"));
- puts(_("\tn\tadd a new partition"));
- puts(_("\to\tcreate a new empty DOS partition table"));
- puts(_("\tp\tprint the partition table"));
- puts(_("\tq\tquit without saving changes"));
- puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
- puts(_("\tt\tchange a partition's system id"));
- puts(_("\tu\tchange display/entry units"));
- puts(_("\tv\tverify the partition table"));
- puts(_("\tw\twrite table to disk and exit"));
-#ifdef CONFIG_FEATURE_FDISK_ADVANCED
- puts(_("\tx\textra functionality (experts only)"));
+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 /* CONFIG_FEATURE_FDISK_WRITABLE */
+#endif /* FEATURE_FDISK_WRITABLE */
-#ifdef CONFIG_FEATURE_FDISK_ADVANCED
+#if ENABLE_FEATURE_FDISK_ADVANCED
static void
-xmenu(void) {
-#ifdef CONFIG_FEATURE_SUN_LABEL
- if (sun_label) {
- puts(_("Command action"));
- puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
- puts(_("\tc\tchange number of cylinders"));
- puts(_("\td\tprint the raw data in the partition table"));
- puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
- puts(_("\th\tchange number of heads"));
- puts(_("\ti\tchange interleave factor")); /*sun*/
- puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
- puts(_("\tm\tprint this menu"));
- puts(_("\tp\tprint the partition table"));
- puts(_("\tq\tquit without saving changes"));
- puts(_("\tr\treturn to main menu"));
- puts(_("\ts\tchange number of sectors/track"));
- puts(_("\tv\tverify the partition table"));
- puts(_("\tw\twrite table to disk and exit"));
- puts(_("\ty\tchange number of physical cylinders")); /*sun*/
- } else
-#endif
-#ifdef CONFIG_FEATURE_SGI_LABEL
- if (sgi_label) {
- puts(_("Command action"));
- puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
- puts(_("\tc\tchange number of cylinders"));
- puts(_("\td\tprint the raw data in the partition table"));
- puts(_("\te\tlist extended partitions")); /* !sun */
- puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
- puts(_("\th\tchange number of heads"));
- puts(_("\tm\tprint this menu"));
- puts(_("\tp\tprint the partition table"));
- puts(_("\tq\tquit without saving changes"));
- puts(_("\tr\treturn to main menu"));
- puts(_("\ts\tchange number of sectors/track"));
- puts(_("\tv\tverify the partition table"));
- puts(_("\tw\twrite table to disk and exit"));
- } else
-#endif
-#ifdef CONFIG_FEATURE_AIX_LABEL
- if (aix_label) {
- puts(_("Command action"));
- puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
- puts(_("\tc\tchange number of cylinders"));
- puts(_("\td\tprint the raw data in the partition table"));
- puts(_("\te\tlist extended partitions")); /* !sun */
- puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
- puts(_("\th\tchange number of heads"));
- puts(_("\tm\tprint this menu"));
- puts(_("\tp\tprint the partition table"));
- puts(_("\tq\tquit without saving changes"));
- puts(_("\tr\treturn to main menu"));
- puts(_("\ts\tchange number of sectors/track"));
- puts(_("\tv\tverify the partition table"));
- puts(_("\tw\twrite table to disk and exit"));
- } else
-#endif
- {
- puts(_("Command action"));
- puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
- puts(_("\tc\tchange number of cylinders"));
- puts(_("\td\tprint the raw data in the partition table"));
- puts(_("\te\tlist extended partitions")); /* !sun */
- puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
-#ifdef CONFIG_FEATURE_SGI_LABEL
- puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
-#endif
- puts(_("\th\tchange number of heads"));
- puts(_("\tm\tprint this menu"));
- puts(_("\tp\tprint the partition table"));
- puts(_("\tq\tquit without saving changes"));
- puts(_("\tr\treturn to main menu"));
- puts(_("\ts\tchange number of sectors/track"));
- puts(_("\tv\tverify the partition table"));
- puts(_("\tw\twrite table to disk and exit"));
+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 */
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
-static const struct systypes *
-get_sys_types(void) {
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static const char *const *
+get_sys_types(void)
+{
return (
-#ifdef CONFIG_FEATURE_SUN_LABEL
- sun_label ? sun_sys_types :
-#endif
-#ifdef CONFIG_FEATURE_SGI_LABEL
- sgi_label ? sgi_sys_types :
-#endif
+ LABEL_IS_SUN ? sun_sys_types :
+ LABEL_IS_SGI ? sgi_sys_types :
i386_sys_types);
}
#else
#define get_sys_types() i386_sys_types
-#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
+#endif /* FEATURE_FDISK_WRITABLE */
-static const char *partition_type(unsigned char type)
+static const char *
+partition_type(unsigned char type)
{
int i;
- const struct systypes *types = get_sys_types();
+ const char *const *types = get_sys_types();
- for (i=0; types[i].name; i++)
- if (types[i].name[0] == type)
- return types[i].name + 1;
+ for (i = 0; types[i]; i++)
+ if ((unsigned char)types[i][0] == type)
+ return types[i] + 1;
- return _("Unknown");
+ return "Unknown";
}
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
+#if ENABLE_FEATURE_FDISK_WRITABLE
static int
-get_sysid(int i) {
- return (
-#ifdef CONFIG_FEATURE_SUN_LABEL
- sun_label ? sunlabel->infos[i].id :
-#endif
-#ifdef CONFIG_FEATURE_SGI_LABEL
- sgi_label ? sgi_get_sysid(i) :
-#endif
- ptes[i].part_table->sys_ind);
+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);
}
-void list_types(const struct systypes *sys)
+static void
+list_types(const char *const *sys)
{
- uint last[4], done = 0, next = 0, size;
+ enum { COLS = 3 };
+
+ unsigned last[COLS];
+ unsigned done, next, size;
int i;
- for (i = 0; sys[i].name; i++);
- size = i;
+ for (size = 0; sys[size]; size++)
+ continue;
- for (i = 3; i >= 0; i--)
- last[3 - i] = done += (size + i - done) / (i + 1);
- i = done = 0;
+ 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 %-15.15s", i ? ' ' : '\n',
- sys[next].name[0], partition_type(sys[next].name[0]));
+ printf("%c%2x %-22.22s", i ? ' ' : '\n',
+ (unsigned char)sys[next][0],
+ sys[next] + 1);
next = last[i++] + done;
- if (i > 3 || next >= last[i]) {
+ if (i >= COLS || next >= last[i]) {
i = 0;
next = ++done;
}
} while (done < last[0]);
- putchar('\n');
+ bb_putchar('\n');
}
-#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
+#endif /* FEATURE_FDISK_WRITABLE */
static int
-is_cleared_partition(const struct partition *p) {
+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) {
+clear_partition(struct partition *p)
+{
if (!p)
return;
memset(p, 0, sizeof(struct partition));
}
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
+#if ENABLE_FEATURE_FDISK_WRITABLE
static void
-set_partition(int i, int doext, uint start, uint stop, int sysid) {
+set_partition(int i, int doext, ullong start, ullong stop, int sysid)
+{
struct partition *p;
- uint offset;
+ ullong offset;
if (doext) {
p = ptes[i].ext_pointer;
@@ -3698,55 +997,41 @@ set_partition(int i, int doext, uint start, uint stop, int sysid) {
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;
+ if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
+ start = g_heads * g_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;
+ if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
+ stop = g_heads * g_sectors * 1024 - 1;
set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
ptes[i].changed = 1;
}
#endif
static int
-test_c(const char **m, const char *mesg) {
- int val = 0;
- if (!*m)
- fprintf(stderr, _("You must set"));
- else {
- fprintf(stderr, " %s", *m);
- val = 1;
- }
- *m = mesg;
- return val;
-}
-
-static int
-warn_geometry(void) {
- const char *m = NULL;
- int prev = 0;
-
- if (!heads)
- prev = test_c(&m, _("heads"));
- if (!sectors)
- prev = test_c(&m, _("sectors"));
- if (!cylinders)
- prev = test_c(&m, _("cylinders"));
- if (!m)
+warn_geometry(void)
+{
+ if (g_heads && g_sectors && g_cylinders)
return 0;
- fprintf(stderr, "%s%s.\n"
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
- "You can do this from the extra functions menu.\n"
-#endif
- , prev ? _(" and ") : " ", m);
-
+ printf("Unknown value(s) for:");
+ if (!g_heads)
+ printf(" heads");
+ if (!g_sectors)
+ printf(" sectors");
+ if (!g_cylinders)
+ printf(" cylinders");
+ printf(
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ " (settable in the extra functions menu)"
+#endif
+ "\n");
return 1;
}
-static void update_units(void)
+static void
+update_units(void)
{
- int cyl_units = heads * sectors;
+ int cyl_units = g_heads * g_sectors;
if (display_in_cyl_units && cyl_units)
units_per_sector = cyl_units;
@@ -3754,23 +1039,25 @@ static void update_units(void)
units_per_sector = 1; /* in sectors */
}
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
+#if ENABLE_FEATURE_FDISK_WRITABLE
static void
-warn_cylinders(void) {
- if (dos_label && cylinders > 1024 && !nowarn)
- fprintf(stderr, _("\n"
+warn_cylinders(void)
+{
+ if (LABEL_IS_DOS && g_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);
+" (e.g., DOS FDISK, OS/2 FDISK)\n",
+ g_cylinders);
}
#endif
static void
-read_extended(int ext) {
+read_extended(int ext)
+{
int i;
struct pte *pex;
struct partition *p, *q;
@@ -3781,23 +1068,21 @@ read_extended(int ext) {
p = pex->part_table;
if (!get_start_sect(p)) {
- fprintf(stderr,
- _("Bad offset in primary extended partition\n"));
+ printf("Bad offset in primary extended partition\n");
return;
}
- while (IS_EXTENDED (p->sys_ind)) {
- struct pte *pe = &ptes[partitions];
+ while (IS_EXTENDED(p->sys_ind)) {
+ struct pte *pe = &ptes[g_partitions];
- if (partitions >= MAXIMUM_PARTS) {
+ if (g_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];
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
- fprintf(stderr,
- _("Warning: deleting partitions after %d\n"),
- partitions);
+ Do not try to 'improve' this test. */
+ struct pte *pre = &ptes[g_partitions - 1];
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ printf("Warning: deleting partitions after %d\n",
+ g_partitions);
pre->changed = 1;
#endif
clear_partition(pre->ext_pointer);
@@ -3811,20 +1096,18 @@ read_extended(int ext) {
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 (IS_EXTENDED(p->sys_ind)) {
if (pe->ext_pointer)
- fprintf(stderr,
- _("Warning: extra link "
- "pointer in partition table"
- " %d\n"), partitions + 1);
+ printf("Warning: extra link "
+ "pointer in partition table"
+ " %d\n", g_partitions + 1);
else
pe->ext_pointer = p;
} else if (p->sys_ind) {
if (pe->part_table)
- fprintf(stderr,
- _("Warning: ignoring extra "
+ printf("Warning: ignoring extra "
"data in partition table"
- " %d\n"), partitions + 1);
+ " %d\n", g_partitions + 1);
else
pe->part_table = p;
}
@@ -3845,18 +1128,19 @@ read_extended(int ext) {
}
p = pe->ext_pointer;
- partitions++;
+ g_partitions++;
}
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
+#if ENABLE_FEATURE_FDISK_WRITABLE
/* remove empty links */
remove:
- for (i = 4; i < partitions; i++) {
+ for (i = 4; i < g_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);
+ if (!get_nr_sects(pe->part_table)
+ && (g_partitions > 5 || ptes[4].part_table->sys_ind)
+ ) {
+ printf("Omitting empty partition (%d)\n", i+1);
delete_partition(i);
goto remove; /* numbering changed */
}
@@ -3864,29 +1148,20 @@ read_extended(int ext) {
#endif
}
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
+#if ENABLE_FEATURE_FDISK_WRITABLE
static void
-create_doslabel(void) {
+create_doslabel(void)
+{
int i;
- fprintf(stderr,
- _("Building a new DOS disklabel. Changes will remain in memory only,\n"
- "until you decide to write them. After that, of course, the previous\n"
- "content won't be recoverable.\n\n"));
-#ifdef CONFIG_FEATURE_SUN_LABEL
- sun_nolabel(); /* otherwise always recognised as sun */
-#endif
-#ifdef CONFIG_FEATURE_SGI_LABEL
- sgi_nolabel(); /* otherwise always recognised as sgi */
-#endif
-#ifdef CONFIG_FEATURE_AIX_LABEL
- aix_label = 0;
-#endif
-#ifdef CONFIG_FEATURE_OSF_LABEL
- osf_label = 0;
+ printf(msg_building_new_label, "DOS disklabel");
+
+ current_label_type = LABEL_DOS;
+
+#if ENABLE_FEATURE_OSF_LABEL
possibly_osf_label = 0;
#endif
- partitions = 4;
+ g_partitions = 4;
for (i = 510-64; i < 510; i++)
MBRbuffer[i] = 0;
@@ -3894,28 +1169,30 @@ create_doslabel(void) {
extended_offset = 0;
set_all_unchanged();
set_changed(0);
- get_boot(create_empty_dos);
+ get_boot(CREATE_EMPTY_DOS);
}
-#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
+#endif /* FEATURE_FDISK_WRITABLE */
static void
-get_sectorsize(void) {
- if (!user_set_sector_size &&
- get_kernel_revision() >= MAKE_VERSION(2,3,3)) {
+get_sectorsize(void)
+{
+ if (!user_set_sector_size) {
int arg;
- if (ioctl(fd, BLKSSZGET, &arg) == 0)
+ if (ioctl(dev_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);
+ printf("Note: sector size is %d "
+ "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
+ sector_size);
}
}
-static inline void
-get_kernel_geometry(void) {
+static void
+get_kernel_geometry(void)
+{
struct hd_geometry geometry;
- if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
+ if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
kern_heads = geometry.heads;
kern_sectors = geometry.sectors;
/* never use geometry.cylinders - it is truncated */
@@ -3923,18 +1200,19 @@ get_kernel_geometry(void) {
}
static void
-get_partition_table_geometry(void) {
- const unsigned char *bufp = MBRbuffer;
+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(bufp)))
+ if (!(valid_part_table_flag((char*)bufp)))
return;
hh = ss = 0;
- for (i=0; i<4; i++) {
+ for (i = 0; i < 4; i++) {
p = pt_offset(bufp, i);
if (p->sys_ind != 0) {
h = p->end_head + 1;
@@ -3954,209 +1232,188 @@ get_partition_table_geometry(void) {
}
}
-void
-get_geometry(void) {
+static void
+get_geometry(void)
+{
int sec_fac;
- unsigned long long bytes; /* really u64 */
get_sectorsize();
sec_fac = sector_size / 512;
-#ifdef CONFIG_FEATURE_SUN_LABEL
+#if ENABLE_FEATURE_SUN_LABEL
guess_device_type();
#endif
- heads = cylinders = sectors = 0;
+ g_heads = g_cylinders = g_sectors = 0;
kern_heads = kern_sectors = 0;
pt_heads = pt_sectors = 0;
get_kernel_geometry();
get_partition_table_geometry();
- heads = user_heads ? user_heads :
+ g_heads = user_heads ? user_heads :
pt_heads ? pt_heads :
kern_heads ? kern_heads : 255;
- sectors = user_sectors ? user_sectors :
+ g_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);
+ total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
sector_offset = 1;
if (dos_compatible_flag)
- sector_offset = sectors;
+ sector_offset = g_sectors;
- cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
- if (!cylinders)
- cylinders = user_cylinders;
+ g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
+ if (!g_cylinders)
+ g_cylinders = user_cylinders;
}
/*
- * Read MBR. Returns:
+ * Opens disk_device and optionally reads MBR.
+ * FIXME: document what each 'what' value will do!
+ * Returns:
* -1: no 0xaa55 flag present (possibly entire disk BSD)
* 0: found or created label
* 1: I/O error
*/
-int
-get_boot(enum action what) {
- int i;
-
- partitions = 4;
+#if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
+static int get_boot(enum action what)
+#else
+static int get_boot(void)
+#define get_boot(what) get_boot()
+#endif
+{
+ int i, fd;
+ g_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;
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
- pe->changed = (what == create_empty_dos);
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ pe->changed = (what == CREATE_EMPTY_DOS);
#endif
}
-#ifdef CONFIG_FEATURE_SUN_LABEL
- if (what == create_empty_sun && check_sun_label())
- return 0;
-#endif
-
- memset(MBRbuffer, 0, 512);
+#if ENABLE_FEATURE_FDISK_WRITABLE
+// ALERT! highly idiotic design!
+// We end up here when we call get_boot() recursively
+// via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
+// or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
+// (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
+// So skip opening device _again_...
+ if (what == CREATE_EMPTY_DOS USE_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
+ goto created_table;
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
- if (what == create_empty_dos)
- goto got_dos_table; /* skip reading disk */
+ fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
- if ((fd = open(disk_device, type_open)) < 0) {
- if ((fd = open(disk_device, O_RDONLY)) < 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 (fd < 0) {
+ fd = open(disk_device, O_RDONLY);
+ if (fd < 0) {
+ if (what == TRY_ONLY)
+ return 1;
+ fdisk_fatal(unable_to_open);
+ }
+ printf("'%s' is opened for read only\n", disk_device);
}
-
- if (512 != read(fd, MBRbuffer, 512)) {
- if (what == try_only)
+ xmove_fd(fd, dev_fd);
+ if (512 != full_read(dev_fd, MBRbuffer, 512)) {
+ if (what == TRY_ONLY) {
+ close_dev_fd();
return 1;
+ }
fdisk_fatal(unable_to_read);
}
#else
- if ((fd = open(disk_device, O_RDONLY)) < 0)
+ fd = open(disk_device, O_RDONLY);
+ if (fd < 0)
return 1;
- if (512 != read(fd, MBRbuffer, 512))
+ if (512 != full_read(fd, MBRbuffer, 512)) {
+ close(fd);
return 1;
+ }
+ xmove_fd(fd, dev_fd);
#endif
get_geometry();
-
update_units();
-#ifdef CONFIG_FEATURE_SUN_LABEL
+#if ENABLE_FEATURE_SUN_LABEL
if (check_sun_label())
return 0;
#endif
-
-#ifdef CONFIG_FEATURE_SGI_LABEL
+#if ENABLE_FEATURE_SGI_LABEL
if (check_sgi_label())
return 0;
#endif
-
-#ifdef CONFIG_FEATURE_AIX_LABEL
+#if ENABLE_FEATURE_AIX_LABEL
if (check_aix_label())
return 0;
#endif
-
-#ifdef CONFIG_FEATURE_OSF_LABEL
+#if ENABLE_FEATURE_OSF_LABEL
if (check_osf_label()) {
possibly_osf_label = 1;
if (!valid_part_table_flag(MBRbuffer)) {
- osf_label = 1;
+ 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"));
+ printf("This disk has both DOS and BSD magic.\n"
+ "Give the 'b' command to go to BSD mode.\n");
}
#endif
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
-got_dos_table:
-#endif
-
- if (!valid_part_table_flag(MBRbuffer)) {
-#ifndef CONFIG_FEATURE_FDISK_WRITABLE
+#if !ENABLE_FEATURE_FDISK_WRITABLE
+ if (!valid_part_table_flag(MBRbuffer))
return -1;
#else
- switch(what) {
- case fdisk:
- fprintf(stderr,
- _("Device contains neither a valid DOS "
+ if (!valid_part_table_flag(MBRbuffer)) {
+ if (what == OPEN_MAIN) {
+ printf("Device contains neither a valid DOS "
"partition table, nor Sun, SGI or OSF "
- "disklabel\n"));
+ "disklabel\n");
#ifdef __sparc__
-#ifdef CONFIG_FEATURE_SUN_LABEL
- create_sunlabel();
-#endif
+ USE_FEATURE_SUN_LABEL(create_sunlabel();)
#else
create_doslabel();
#endif
return 0;
- case try_only:
- return -1;
- case create_empty_dos:
-#ifdef CONFIG_FEATURE_SUN_LABEL
- case create_empty_sun:
-#endif
- break;
- default:
- fprintf(stderr, _("Internal error\n"));
- exit(1);
}
-#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
+ /* TRY_ONLY: */
+ return -1;
}
+ created_table:
+#endif /* FEATURE_FDISK_WRITABLE */
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
- warn_cylinders();
-#endif
+
+ USE_FEATURE_FDISK_WRITABLE(warn_cylinders();)
warn_geometry();
for (i = 0; i < 4; i++) {
- struct pte *pe = &ptes[i];
-
- if (IS_EXTENDED (pe->part_table->sys_ind)) {
- if (partitions != 4)
- fprintf(stderr, _("Ignoring extra extended "
- "partition %d\n"), i + 1);
+ if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
+ if (g_partitions != 4)
+ printf("Ignoring extra extended "
+ "partition %d\n", i + 1);
else
read_extended(i);
}
}
- for (i = 3; i < partitions; i++) {
+ for (i = 3; i < g_partitions; i++) {
struct pte *pe = &ptes[i];
-
if (!valid_part_table_flag(pe->sectorbuffer)) {
- fprintf(stderr,
- _("Warning: invalid flag 0x%04x of partition "
- "table %d will be corrected by w(rite)\n"),
- part_table_flag(pe->sectorbuffer), i + 1);
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
- pe->changed = 1;
-#endif
+ 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);
+ USE_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
}
}
return 0;
}
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
+#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.
@@ -4164,127 +1421,114 @@ got_dos_table:
*
* There is no default if DFLT is not between LOW and HIGH.
*/
-static uint
-read_int(uint low, uint dflt, uint high, uint base, char *mesg)
+static unsigned
+read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg)
{
- uint i;
+ unsigned i;
int default_ok = 1;
- static char *ms = NULL;
- static int mslen = 0;
+ const char *fmt = "%s (%u-%u, default %u): ";
- if (!ms || strlen(mesg)+100 > mslen) {
- mslen = strlen(mesg)+200;
- ms = xrealloc(ms,mslen);
- }
-
- if (dflt < low || dflt > high)
+ if (dflt < low || dflt > high) {
+ fmt = "%s (%u-%u): ";
default_ok = 0;
-
- if (default_ok)
- snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
- mesg, low, high, dflt);
- else
- snprintf(ms, mslen, "%s (%u-%u): ",
- mesg, low, high);
+ }
while (1) {
int use_default = default_ok;
/* ask question and read answer */
- while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
- && *line_ptr != '-' && *line_ptr != '+')
- continue;
+ 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;
- 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;
+ 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 *= g_heads * g_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 (minus)
- i = -i;
- i += base;
- } else {
+ if (absolute) {
+ ullong bytes;
+ unsigned long unit;
+
+ bytes = (ullong) 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)
- printf(_("Using default value %u\n"), i = dflt);
+ if (use_default) {
+ i = dflt;
+ printf("Using default value %u\n", i);
+ }
if (i >= low && i <= high)
break;
- else
- printf(_("Value out of range.\n"));
+ printf("Value is out of range\n");
}
return i;
}
-int
-get_partition(int warn, int max) {
+static int
+get_partition(int warn, int max)
+{
struct pte *pe;
int i;
- i = read_int(1, 0, max, 0, _("Partition number")) - 1;
+ i = read_int(1, 0, max, 0, "Partition number") - 1;
pe = &ptes[i];
if (warn) {
- if ((!sun_label && !sgi_label && !pe->part_table->sys_ind)
-#ifdef CONFIG_FEATURE_SUN_LABEL
- || (sun_label &&
- (!sunlabel->partitions[i].num_sectors ||
- !sunlabel->infos[i].id))
-#endif
-#ifdef CONFIG_FEATURE_SGI_LABEL
- || (sgi_label && (!sgi_get_num_sectors(i)))
-#endif
- )
- fprintf(stderr,
- _("Warning: partition %d has empty type\n"),
- i+1);
+ 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) {
+get_existing_partition(int warn, int max)
+{
int pno = -1;
int i;
@@ -4299,10 +1543,10 @@ get_existing_partition(int warn, int max) {
}
}
if (pno >= 0) {
- printf(_("Selected partition %d\n"), pno+1);
+ printf("Selected partition %d\n", pno+1);
return pno;
}
- printf(_("No partition is defined yet!\n"));
+ printf("No partition is defined yet!\n");
return -1;
not_unique:
@@ -4310,7 +1554,8 @@ get_existing_partition(int warn, int max) {
}
static int
-get_nonexisting_partition(int warn, int max) {
+get_nonexisting_partition(int warn, int max)
+{
int pno = -1;
int i;
@@ -4325,10 +1570,10 @@ get_nonexisting_partition(int warn, int max) {
}
}
if (pno >= 0) {
- printf(_("Selected partition %d\n"), pno+1);
+ printf("Selected partition %d\n", pno+1);
return pno;
}
- printf(_("All primary partitions have been defined already!\n"));
+ printf("All primary partitions have been defined already!\n");
return -1;
not_unique:
@@ -4336,42 +1581,43 @@ get_nonexisting_partition(int warn, int max) {
}
-void change_units(void)
+static void
+change_units(void)
{
display_in_cyl_units = !display_in_cyl_units;
update_units();
- printf(_("Changing display/entry units to %s\n"),
+ printf("Changing display/entry units to %s\n",
str_units(PLURAL));
}
static void
-toggle_active(int i) {
+toggle_active(int i)
+{
struct pte *pe = &ptes[i];
struct partition *p = pe->part_table;
- if (IS_EXTENDED (p->sys_ind) && !p->boot_ind)
- fprintf(stderr,
- _("WARNING: Partition %d is an extended partition\n"),
- i + 1);
+ 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;
+toggle_dos_compatibility_flag(void)
+{
+ dos_compatible_flag = 1 - dos_compatible_flag;
if (dos_compatible_flag) {
- sector_offset = sectors;
- printf(_("DOS Compatibility flag is set\n"));
- }
- else {
+ sector_offset = g_sectors;
+ printf("DOS Compatibility flag is set\n");
+ } else {
sector_offset = 1;
- printf(_("DOS Compatibility flag is not set\n"));
+ printf("DOS Compatibility flag is not set\n");
}
}
static void
-delete_partition(int i) {
+delete_partition(int i)
+{
struct pte *pe = &ptes[i];
struct partition *p = pe->part_table;
struct partition *q = pe->ext_pointer;
@@ -4384,22 +1630,18 @@ delete_partition(int i) {
return; /* C/H/S not set */
pe->changed = 1;
-#ifdef CONFIG_FEATURE_SUN_LABEL
- if (sun_label) {
+ if (LABEL_IS_SUN) {
sun_delete_partition(i);
return;
}
-#endif
-#ifdef CONFIG_FEATURE_SGI_LABEL
- if (sgi_label) {
+ if (LABEL_IS_SGI) {
sgi_delete_partition(i);
return;
}
-#endif
if (i < 4) {
- if (IS_EXTENDED (p->sys_ind) && i == ext_index) {
- partitions = 4;
+ if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
+ g_partitions = 4;
ptes[ext_index].ext_pointer = NULL;
extended_offset = 0;
}
@@ -4409,7 +1651,7 @@ delete_partition(int i) {
if (!q->sys_ind && i > 4) {
/* the last one in the chain - just delete */
- --partitions;
+ --g_partitions;
--i;
clear_partition(ptes[i].ext_pointer);
ptes[i].changed = 1;
@@ -4422,21 +1664,21 @@ delete_partition(int i) {
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 */
+ } else if (g_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);
+ get_partition_start(pe) -
+ extended_offset);
pe->offset = extended_offset;
pe->changed = 1;
}
- if (partitions > 5) {
- partitions--;
- while (i < partitions) {
+ if (g_partitions > 5) {
+ g_partitions--;
+ while (i < g_partitions) {
ptes[i] = ptes[i+1];
i++;
}
@@ -4447,22 +1689,19 @@ delete_partition(int i) {
}
static void
-change_sysid(void) {
+change_sysid(void)
+{
int i, sys, origsys;
struct partition *p;
-#ifdef CONFIG_FEATURE_SGI_LABEL
/* 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 (!sgi_label) {
- i = get_existing_partition(0, partitions);
+ if (!LABEL_IS_SGI) {
+ i = get_existing_partition(0, g_partitions);
} else {
- i = get_partition(0, partitions);
+ i = get_partition(0, g_partitions);
}
-#else
- i = get_existing_partition(0, partitions);
-#endif
if (i == -1)
return;
p = ptes[i].part_table;
@@ -4470,92 +1709,96 @@ change_sysid(void) {
/* if changing types T to 0 is allowed, then
the reverse change must be allowed, too */
- if (!sys && !sgi_label && !sun_label && !get_nr_sects(p))
- printf(_("Partition %d does not exist yet!\n"), i + 1);
- else while (1) {
- sys = read_hex (get_sys_types());
-
- if (!sys && !sgi_label && !sun_label) {
- printf(_("Type 0 means free space to many systems\n"
- "(but not to Linux). Having partitions of\n"
- "type 0 is probably unwise. You can delete\n"
- "a partition using the `d' command.\n"));
+ 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 (!sun_label && !sgi_label) {
- if (IS_EXTENDED (sys) != IS_EXTENDED (p->sys_ind)) {
- printf(_("You cannot change a partition into"
- " an extended one or vice versa\n"
- "Delete it first.\n"));
+ 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) {
-#ifdef CONFIG_FEATURE_SUN_LABEL
- if (sun_label && i == 2 && sys != WHOLE_DISK)
- printf(_("Consider leaving partition 3 "
- "as Whole disk (5),\n"
- "as SunOS/Solaris expects it and "
- "even Linux likes it.\n\n"));
-#endif
-#ifdef CONFIG_FEATURE_SGI_LABEL
- if (sgi_label && ((i == 10 && sys != ENTIRE_DISK)
- || (i == 8 && sys != 0)))
- printf(_("Consider leaving partition 9 "
- "as volume header (0),\nand "
- "partition 11 as entire volume (6)"
- "as IRIX expects it.\n\n"));
+#if 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;
-#ifdef CONFIG_FEATURE_SUN_LABEL
- if (sun_label) {
+ if (LABEL_IS_SUN) {
sun_change_sysid(i, sys);
- } else
-#endif
-#ifdef CONFIG_FEATURE_SGI_LABEL
- if (sgi_label) {
+ } else if (LABEL_IS_SGI) {
sgi_change_sysid(i, sys);
} else
-#endif
p->sys_ind = sys;
- printf (_("Changed system type of partition %d "
- "to %x (%s)\n"), i + 1, 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;
+ //if (is_dos_partition(origsys) || is_dos_partition(sys))
+ // dos_changed = 1;
break;
}
}
}
-#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
+#endif /* FEATURE_FDISK_WRITABLE */
-/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
+/* 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 long2chs(ulong ls, uint *c, uint *h, uint *s) {
- int spc = heads * sectors;
+static void
+linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
+{
+ int spc = g_heads * g_sectors;
*c = ls / spc;
ls = ls % spc;
- *h = ls / sectors;
- *s = ls % sectors + 1; /* sectors count from 1 */
+ *h = ls / g_sectors;
+ *s = ls % g_sectors + 1; /* sectors count from 1 */
}
-static void check_consistency(const struct partition *p, int partition) {
- uint pbc, pbh, pbs; /* physical beginning c, h, s */
- uint pec, peh, pes; /* physical ending c, h, s */
- uint lbc, lbh, lbs; /* logical beginning c, h, s */
- uint lec, leh, les; /* logical ending c, h, s */
+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))
+ if (!g_heads || !g_sectors || (partition >= 4))
return; /* do not check extended partitions */
/* physical beginning c, h, s */
@@ -4569,68 +1812,54 @@ static void check_consistency(const struct partition *p, int partition) {
pes = p->end_sector & 0x3f;
/* compute logical beginning (c, h, s) */
- long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
+ linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
/* compute logical ending (c, h, s) */
- long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
+ 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);
+ if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
+ printf("Partition %d has different physical/logical "
+ "beginnings (non-Linux?):\n", partition + 1);
+ printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs);
+ printf("logical=(%d, %d, %d)\n", lbc, lbh, lbs);
}
/* Same physical / logical ending? */
- if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
- printf(_("Partition %d has different physical/logical "
- "endings:\n"), partition + 1);
- printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
- printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
+ if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
+ printf("Partition %d has different physical/logical "
+ "endings:\n", partition + 1);
+ printf(" phys=(%d, %d, %d) ", pec, peh, pes);
+ printf("logical=(%d, %d, %d)\n", lec, leh, les);
}
-#if 0
-/* Beginning on cylinder boundary? */
- if (pbh != !pbc || pbs != 1) {
- printf(_("Partition %i does not start on cylinder "
- "boundary:\n"), partition + 1);
- printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
- printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
- }
-#endif
-
/* Ending on cylinder boundary? */
- if (peh != (heads - 1) || pes != sectors) {
- printf(_("Partition %i does not end on cylinder boundary.\n"),
+ if (peh != (g_heads - 1) || pes != g_sectors) {
+ printf("Partition %i does not end on cylinder boundary\n",
partition + 1);
-#if 0
- printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
- printf(_("should be (%d, %d, %d)\n"),
- pec, heads - 1, sectors);
-#endif
}
}
static void
-list_disk_geometry(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);
+ 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);
+ 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",
+ g_heads, g_sectors, g_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);
+ 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);
}
/*
@@ -4639,19 +1868,21 @@ list_disk_geometry(void) {
* Two separate checks: primary and logical partitions.
*/
static int
-wrong_p_order(int *prev) {
+wrong_p_order(int *prev)
+{
const struct pte *pe;
const struct partition *p;
- uint last_p_start_pos = 0, p_start_pos;
+ ullong last_p_start_pos = 0, p_start_pos;
int i, last_i = 0;
- for (i = 0 ; i < partitions; i++) {
+ for (i = 0; i < g_partitions; i++) {
if (i == 4) {
last_i = 4;
last_p_start_pos = 0;
}
pe = &ptes[i];
- if ((p = pe->part_table)->sys_ind) {
+ p = pe->part_table;
+ if (p->sys_ind) {
p_start_pos = get_partition_start(pe);
if (last_p_start_pos > p_start_pos) {
@@ -4667,7 +1898,7 @@ wrong_p_order(int *prev) {
return 0;
}
-#ifdef CONFIG_FEATURE_FDISK_ADVANCED
+#if ENABLE_FEATURE_FDISK_ADVANCED
/*
* Fix the chain of logicals.
* extended_offset is unchanged, the set of sectors used is unchanged
@@ -4682,14 +1913,15 @@ wrong_p_order(int *prev) {
* may help.
*/
static void
-fix_chain_of_logicals(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++) {
+ for (j = 5; j < g_partitions - 1; j++) {
oj = ptes[j].offset;
ojj = ptes[j+1].offset;
if (oj > ojj) {
@@ -4700,16 +1932,16 @@ fix_chain_of_logicals(void) {
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);
+ ojj-extended_offset);
set_start_sect(ptes[j].ext_pointer,
- oj-extended_offset);
+ oj-extended_offset);
goto stage1;
}
}
/* Stage 2: sort starting sectors */
stage2:
- for (j = 4; j < partitions-1; j++) {
+ for (j = 4; j < g_partitions - 1; j++) {
pj = ptes[j].part_table;
pjj = ptes[j+1].part_table;
sj = get_start_sect(pj);
@@ -4727,18 +1959,19 @@ fix_chain_of_logicals(void) {
}
/* Probably something was changed */
- for (j = 4; j < partitions; j++)
+ for (j = 4; j < g_partitions; j++)
ptes[j].changed = 1;
}
static void
-fix_partition_table_order(void) {
+fix_partition_table_order(void)
+{
struct pte *pei, *pek;
int i,k;
if (!wrong_p_order(NULL)) {
- printf(_("Nothing to do. Ordering is correct already.\n\n"));
+ printf("Ordering is already correct\n\n");
return;
}
@@ -4772,32 +2005,26 @@ fix_partition_table_order(void) {
#endif
static void
-list_table(int xtra) {
+list_table(int xtra)
+{
const struct partition *p;
int i, w;
-#ifdef CONFIG_FEATURE_SUN_LABEL
- if (sun_label) {
+ if (LABEL_IS_SUN) {
sun_list_table(xtra);
return;
}
-#endif
-
-#ifdef CONFIG_FEATURE_SGI_LABEL
- if (sgi_label) {
+ if (LABEL_IS_SUN) {
sgi_list_table(xtra);
return;
}
-#endif
list_disk_geometry();
-#ifdef CONFIG_FEATURE_OSF_LABEL
- if (osf_label) {
+ if (LABEL_IS_OSF) {
xbsd_print_disklabel(xtra);
return;
}
-#endif
/* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
but if the device name ends in a digit, say /dev/foo1,
@@ -4808,58 +2035,66 @@ list_table(int xtra) {
if (w < 5)
w = 5;
- printf(_("%*s Boot Start End Blocks Id System\n"),
- w+1, _("Device"));
+ // 1 12345678901 12345678901 12345678901 12
+ printf("%*s Boot Start End Blocks Id System\n",
+ w+1, "Device");
- for (i = 0; i < partitions; i++) {
+ for (i = 0; i < g_partitions; i++) {
const struct pte *pe = &ptes[i];
+ ullong psects;
+ ullong pblocks;
+ unsigned podd;
p = pe->part_table;
- if (p && !is_cleared_partition(p)) {
- unsigned int psects = get_nr_sects(p);
- unsigned int pblocks = psects;
- unsigned int podd = 0;
+ if (!p || is_cleared_partition(p))
+ continue;
- if (sector_size < 1024) {
- pblocks /= (1024 / sector_size);
- podd = psects % (1024 / sector_size);
- }
- if (sector_size > 1024)
- pblocks *= (sector_size / 1024);
- printf(
- "%s %c %11lu %11lu %11lu%c %2x %s\n",
+ 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),
-/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
- ? '*' : '?',
-/* start */ (unsigned long) cround(get_partition_start(pe)),
-/* end */ (unsigned long) cround(get_partition_start(pe) + psects
+ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
+ ? '*' : '?',
+ (ullong) cround(get_partition_start(pe)), /* start */
+ (ullong) cround(get_partition_start(pe) + psects /* end */
- (psects ? 1 : 0)),
-/* odd flag on end */ (unsigned long) pblocks, podd ? '+' : ' ',
-/* type id */ p->sys_ind,
-/* type name */ partition_type(p->sys_ind));
- check_consistency(p, i);
- }
+ (ullong) 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 (dos_label && wrong_p_order(NULL)) {
- printf(_("\nPartition table entries are not in disk order\n"));
+ if (LABEL_IS_DOS && wrong_p_order(NULL)) {
+ /* FIXME */
+ printf("\nPartition table entries are not in disk order\n");
}
}
-#ifdef CONFIG_FEATURE_FDISK_ADVANCED
+#if ENABLE_FEATURE_FDISK_ADVANCED
static void
-x_list_table(int extend) {
+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++) {
+ printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n",
+ disk_device, g_heads, g_sectors, g_cylinders);
+ printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
+ for (i = 0; i < g_partitions; i++) {
pe = &ptes[i];
p = (extend ? pe->ext_pointer : pe->part_table);
if (p != NULL) {
@@ -4877,16 +2112,17 @@ x_list_table(int extend) {
}
#endif
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
+#if ENABLE_FEATURE_FDISK_WRITABLE
static void
-fill_bounds(uint *first, uint *last) {
+fill_bounds(ullong *first, ullong *last)
+{
int i;
const struct pte *pe = &ptes[0];
const struct partition *p;
- for (i = 0; i < partitions; pe++,i++) {
+ for (i = 0; i < g_partitions; pe++,i++) {
p = pe->part_table;
- if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) {
+ if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
first[i] = 0xffffffff;
last[i] = 0;
} else {
@@ -4897,131 +2133,127 @@ fill_bounds(uint *first, uint *last) {
}
static void
-check(int n, uint h, uint s, uint c, uint start) {
- uint total, real_s, real_c;
+check(int n, unsigned h, unsigned s, unsigned c, ullong start)
+{
+ ullong total, real_s, real_c;
real_s = sector(s) - 1;
real_c = cylinder(s, c);
- total = (real_c * sectors + real_s) * heads + h;
+ total = (real_c * g_sectors + real_s) * g_heads + h;
if (!total)
- fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
- if (h >= heads)
- fprintf(stderr,
- _("Partition %d: head %d greater than maximum %d\n"),
- n, h + 1, heads);
- if (real_s >= sectors)
- fprintf(stderr, _("Partition %d: sector %d greater than "
- "maximum %d\n"), n, s, sectors);
- if (real_c >= cylinders)
- fprintf(stderr, _("Partitions %d: cylinder %d greater than "
- "maximum %d\n"), n, real_c + 1, cylinders);
- if (cylinders <= 1024 && start != total)
- fprintf(stderr,
- _("Partition %d: previous sectors %d disagrees with "
- "total %d\n"), n, start, total);
-}
-
-static void
-verify(void) {
+ printf("Partition %d contains sector 0\n", n);
+ if (h >= g_heads)
+ printf("Partition %d: head %d greater than maximum %d\n",
+ n, h + 1, g_heads);
+ if (real_s >= g_sectors)
+ printf("Partition %d: sector %d greater than "
+ "maximum %d\n", n, s, g_sectors);
+ if (real_c >= g_cylinders)
+ printf("Partition %d: cylinder %llu greater than "
+ "maximum %d\n", n, real_c + 1, g_cylinders);
+ if (g_cylinders <= 1024 && start != total)
+ printf("Partition %d: previous sectors %llu disagrees with "
+ "total %llu\n", n, start, total);
+}
+
+static void
+verify(void)
+{
int i, j;
- uint total = 1;
- uint first[partitions], last[partitions];
+ unsigned total = 1;
+ ullong first[g_partitions], last[g_partitions];
struct partition *p;
if (warn_geometry())
return;
-#ifdef CONFIG_FEATURE_SUN_LABEL
- if (sun_label) {
+ if (LABEL_IS_SUN) {
verify_sun();
return;
}
-#endif
-#ifdef CONFIG_FEATURE_SGI_LABEL
- if (sgi_label) {
+ if (LABEL_IS_SGI) {
verify_sgi(1);
return;
}
-#endif
fill_bounds(first, last);
- for (i = 0; i < partitions; i++) {
+ for (i = 0; i < g_partitions; i++) {
struct pte *pe = &ptes[i];
p = pe->part_table;
- if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) {
+ 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);
+ 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];
+ 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];
- uint e_last = get_start_sect(pex->part_table) +
+ ullong e_last = get_start_sect(pex->part_table) +
get_nr_sects(pex->part_table) - 1;
- for (i = 4; i < partitions; i++) {
+ for (i = 4; i < g_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);
+ if (i != 4 || i + 1 < g_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);
}
- else if (first[i] < extended_offset ||
- last[i] > e_last)
- printf(_("Logical partition %d not entirely in "
- "partition %d\n"), i + 1, ext_index + 1);
}
}
- if (total > heads * sectors * cylinders)
- printf(_("Total allocated sectors %d greater than the maximum "
- "%d\n"), total, heads * sectors * cylinders);
- else if ((total = heads * sectors * cylinders - total) != 0)
- printf(_("%d unallocated sectors\n"), total);
+ if (total > g_heads * g_sectors * g_cylinders)
+ printf("Total allocated sectors %d greater than the maximum "
+ "%d\n", total, g_heads * g_sectors * g_cylinders);
+ else {
+ total = g_heads * g_sectors * g_cylinders - total;
+ if (total != 0)
+ printf("%d unallocated sectors\n", total);
+ }
}
static void
-add_partition(int n, int sys) {
+add_partition(int n, int sys)
+{
char mesg[256]; /* 48 does not suffice in Japanese */
- int i, readed = 0;
+ int i, num_read = 0;
struct partition *p = ptes[n].part_table;
struct partition *q = ptes[ext_index].part_table;
- long long llimit;
- uint start, stop = 0, limit, temp,
- first[partitions], last[partitions];
+ ullong limit, temp;
+ ullong start, stop = 0;
+ ullong first[g_partitions], last[g_partitions];
if (p && p->sys_ind) {
- printf(_("Partition %d is already defined. Delete "
- "it before re-adding it.\n"), n + 1);
+ 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;
+ limit = (ullong) g_heads * g_sectors * g_cylinders - 1;
else
- llimit = total_number_of_sectors - 1;
- limit = llimit;
- if (limit != llimit)
- limit = 0x7fffffff;
+ limit = total_number_of_sectors - 1;
if (extended_offset) {
first[ext_index] = extended_offset;
last[ext_index] = get_start_sect(q) +
@@ -5032,30 +2264,30 @@ add_partition(int n, int sys) {
limit = get_start_sect(q) + get_nr_sects(q) - 1;
}
if (display_in_cyl_units)
- for (i = 0; i < partitions; i++)
+ for (i = 0; i < g_partitions; i++)
first[i] = (cround(first[i]) - 1) * units_per_sector;
- snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
+ snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
do {
temp = start;
- for (i = 0; i < partitions; i++) {
+ for (i = 0; i < g_partitions; i++) {
int lastplusoff;
if (start == ptes[i].offset)
start += sector_offset;
- lastplusoff = last[i] + ((n<4) ? 0 : 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 && readed) {
- printf(_("Sector %d is already allocated\n"), temp);
+ if (start >= temp+units_per_sector && num_read) {
+ printf("Sector %lld is already allocated\n", temp);
temp = start;
- readed = 0;
+ num_read = 0;
}
- if (!readed && start == temp) {
- uint saved_start;
+ if (!num_read && start == temp) {
+ ullong saved_start;
saved_start = start;
start = read_int(cround(saved_start), cround(saved_start), cround(limit),
@@ -5064,9 +2296,9 @@ add_partition(int n, int sys) {
start = (start - 1) * units_per_sector;
if (start < saved_start) start = saved_start;
}
- readed = 1;
+ num_read = 1;
}
- } while (start != temp || !readed);
+ } while (start != temp || !num_read);
if (n > 4) { /* NOT for fifth partition */
struct pte *pe = &ptes[n];
@@ -5078,7 +2310,7 @@ add_partition(int n, int sys) {
}
}
- for (i = 0; i < partitions; i++) {
+ for (i = 0; i < g_partitions; i++) {
struct pte *pe = &ptes[i];
if (start < pe->offset && limit >= pe->offset)
@@ -5087,16 +2319,16 @@ add_partition(int n, int sys) {
limit = first[i] - 1;
}
if (start > limit) {
- printf(_("No free sectors available\n"));
+ printf("No free sectors available\n");
if (n > 4)
- partitions--;
+ g_partitions--;
return;
}
if (cround(start) == cround(limit)) {
stop = limit;
} else {
snprintf(mesg, sizeof(mesg),
- _("Last %s or +size or +sizeM or +sizeK"),
+ "Last %s or +size or +sizeM or +sizeK",
str_units(SINGULAR));
stop = read_int(cround(start), cround(limit), cround(limit),
cround(start), mesg);
@@ -5111,119 +2343,116 @@ add_partition(int n, int sys) {
if (n > 4)
set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
- if (IS_EXTENDED (sys)) {
+ 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 = xcalloc(1, sector_size);
+ 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;
+ g_partitions = 5;
}
}
static void
-add_logical(void) {
- if (partitions > 5 || ptes[4].part_table->sys_ind) {
- struct pte *pe = &ptes[partitions];
+add_logical(void)
+{
+ if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
+ struct pte *pe = &ptes[g_partitions];
- pe->sectorbuffer = xcalloc(1, sector_size);
+ 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++;
+ g_partitions++;
}
- add_partition(partitions - 1, LINUX_NATIVE);
+ add_partition(g_partitions - 1, LINUX_NATIVE);
}
static void
-new_partition(void) {
+new_partition(void)
+{
int i, free_primary = 0;
if (warn_geometry())
return;
-#ifdef CONFIG_FEATURE_SUN_LABEL
- if (sun_label) {
- add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
+ if (LABEL_IS_SUN) {
+ add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
return;
}
-#endif
-#ifdef CONFIG_FEATURE_SGI_LABEL
- if (sgi_label) {
- sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
+ if (LABEL_IS_SGI) {
+ sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
return;
}
-#endif
-#ifdef CONFIG_FEATURE_AIX_LABEL
- if (aix_label) {
- printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
- "\n\tIf you want to add DOS-type partitions, create"
- "\n\ta new empty DOS partition table first. (Use o.)"
- "\n\tWARNING: "
- "This will destroy the present disk contents.\n"));
+ 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;
}
-#endif
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 && g_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"));
+ printf("You must delete some partition and add "
+ "an extended partition first\n");
} else {
- char c, line[LINE_LENGTH];
- snprintf(line, sizeof(line), "%s\n %s\n p primary "
- "partition (1-4)\n",
- "Command action", (extended_offset ?
- "l logical (5 or over)" : "e extended"));
+ 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) {
- if ((c = read_char(line)) == 'p' || c == 'P') {
+ c = read_nonempty(line);
+ if (c == 'p' || c == 'P') {
i = get_nonexisting_partition(0, 4);
if (i >= 0)
add_partition(i, LINUX_NATIVE);
return;
}
- else if (c == 'l' && extended_offset) {
+ if (c == 'l' && extended_offset) {
add_logical();
return;
}
- else if (c == 'e' && !extended_offset) {
+ if (c == 'e' && !extended_offset) {
i = get_nonexisting_partition(0, 4);
if (i >= 0)
add_partition(i, EXTENDED);
return;
}
- else
- printf(_("Invalid partition number "
- "for type `%c'\n"), c);
+ printf("Invalid partition number "
+ "for type '%c'\n", c);
}
}
}
static void
-write_table(void) {
+write_table(void)
+{
int i;
- if (dos_label) {
- for (i=0; i<3; 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++) {
+ for (i = 3; i < g_partitions; i++) {
struct pte *pe = &ptes[i];
if (pe->changed) {
@@ -5232,125 +2461,102 @@ write_table(void) {
}
}
}
-#ifdef CONFIG_FEATURE_SGI_LABEL
- else if (sgi_label) {
+ else if (LABEL_IS_SGI) {
/* no test on change? the printf below might be mistaken */
sgi_write_table();
}
-#endif
-#ifdef CONFIG_FEATURE_SUN_LABEL
- else if (sun_label) {
+ else if (LABEL_IS_SUN) {
int needw = 0;
- for (i=0; i<8; i++)
+ for (i = 0; i < 8; i++)
if (ptes[i].changed)
needw = 1;
if (needw)
sun_write_table();
}
-#endif
- printf(_("The partition table has been altered!\n\n"));
+ printf("The partition table has been altered!\n\n");
reread_partition_table(1);
}
-void
-reread_partition_table(int leave) {
- int error = 0;
+static void
+reread_partition_table(int leave)
+{
int i;
- printf(_("Calling ioctl() to re-read partition table.\n"));
+ printf("Calling ioctl() to re-read partition table\n");
sync();
- sleep(2);
- if ((i = ioctl(fd, BLKRRPART)) != 0) {
- error = errno;
- } else {
- /* some kernel versions (1.2.x) seem to have trouble
- rereading the partition table, but if asked to do it
- twice, the second time works. - biro@yggdrasil.com */
- sync();
- sleep(2);
- if ((i = ioctl(fd, BLKRRPART)) != 0)
- error = errno;
- }
-
- if (i) {
- printf(_("\nWARNING: Re-reading the partition table "
- "failed with error %d: %s.\n"
- "The kernel still uses the old table.\n"
- "The new table will be used "
- "at the next reboot.\n"),
- error, strerror(error));
- }
-
+ /* sleep(2); Huh? */
+ i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
+ "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"
+ 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"));
+ "information\n");
+#endif
if (leave) {
- close(fd);
-
- printf(_("Syncing disks.\n"));
- sync();
- sleep(4); /* for sync() */
- exit(!!i);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close_dev_fd();
+ exit(i != 0);
}
}
-#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
+#endif /* FEATURE_FDISK_WRITABLE */
-#ifdef CONFIG_FEATURE_FDISK_ADVANCED
+#if ENABLE_FEATURE_FDISK_ADVANCED
#define MAX_PER_LINE 16
static void
-print_buffer(char pbuffer[]) {
- int i,
- l;
+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) {
- printf("\n");
+ bb_putchar('\n');
l = -1;
}
}
if (l > 0)
- printf("\n");
- printf("\n");
+ bb_putchar('\n');
+ bb_putchar('\n');
}
-
static void
-print_raw(void) {
+print_raw(void)
+{
int i;
- printf(_("Device: %s\n"), disk_device);
-#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
- if (sun_label || sgi_label)
+ printf("Device: %s\n", disk_device);
+ if (LABEL_IS_SGI || LABEL_IS_SUN)
print_buffer(MBRbuffer);
- else
-#endif
- for (i = 3; i < partitions; i++)
+ else {
+ for (i = 3; i < g_partitions; i++)
print_buffer(ptes[i].sectorbuffer);
+ }
}
static void
-move_begin(int i) {
+move_begin(int i)
+{
struct pte *pe = &ptes[i];
struct partition *p = pe->part_table;
- uint new, first;
+ ullong 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);
+ 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;
+ "New beginning of data") - pe->offset;
if (new != get_nr_sects(p)) {
first = get_nr_sects(p) + get_start_sect(p) - new;
@@ -5361,99 +2567,84 @@ move_begin(int i) {
}
static void
-xselect(void) {
+xselect(void)
+{
char c;
- while(1) {
- putchar('\n');
- c = tolower(read_char(_("Expert command (m for help): ")));
+ while (1) {
+ bb_putchar('\n');
+ c = tolower(read_nonempty("Expert command (m for help): "));
switch (c) {
case 'a':
-#ifdef CONFIG_FEATURE_SUN_LABEL
- if (sun_label)
+ if (LABEL_IS_SUN)
sun_set_alt_cyl();
-#endif
break;
case 'b':
- if (dos_label)
- move_begin(get_partition(0, partitions));
+ if (LABEL_IS_DOS)
+ move_begin(get_partition(0, g_partitions));
break;
case 'c':
- user_cylinders = cylinders =
- read_int(1, cylinders, 1048576, 0,
- _("Number of cylinders"));
-#ifdef CONFIG_FEATURE_SUN_LABEL
- if (sun_label)
- sun_set_ncyl(cylinders);
-#endif
- if (dos_label)
+ user_cylinders = g_cylinders =
+ read_int(1, g_cylinders, 1048576, 0,
+ "Number of cylinders");
+ if (LABEL_IS_SUN)
+ sun_set_ncyl(g_cylinders);
+ if (LABEL_IS_DOS)
warn_cylinders();
break;
case 'd':
print_raw();
break;
case 'e':
-#ifdef CONFIG_FEATURE_SGI_LABEL
- if (sgi_label)
+ if (LABEL_IS_SGI)
sgi_set_xcyl();
- else
-#endif
-#ifdef CONFIG_FEATURE_SUN_LABEL
- if (sun_label)
+ else if (LABEL_IS_SUN)
sun_set_xcyl();
- else
-#endif
- if (dos_label)
+ else if (LABEL_IS_DOS)
x_list_table(1);
break;
case 'f':
- if (dos_label)
+ if (LABEL_IS_DOS)
fix_partition_table_order();
break;
case 'g':
-#ifdef CONFIG_FEATURE_SGI_LABEL
+#if ENABLE_FEATURE_SGI_LABEL
create_sgilabel();
#endif
break;
case 'h':
- user_heads = heads = read_int(1, heads, 256, 0,
- _("Number of heads"));
+ user_heads = g_heads = read_int(1, g_heads, 256, 0,
+ "Number of heads");
update_units();
break;
case 'i':
-#ifdef CONFIG_FEATURE_SUN_LABEL
- if (sun_label)
+ if (LABEL_IS_SUN)
sun_set_ilfact();
-#endif
break;
case 'o':
-#ifdef CONFIG_FEATURE_SUN_LABEL
- if (sun_label)
+ if (LABEL_IS_SUN)
sun_set_rspeed();
-#endif
break;
case 'p':
-#ifdef CONFIG_FEATURE_SUN_LABEL
- if (sun_label)
+ if (LABEL_IS_SUN)
list_table(1);
else
-#endif
x_list_table(0);
break;
case 'q':
- close(fd);
- printf("\n");
- exit(0);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close_dev_fd();
+ bb_putchar('\n');
+ exit(EXIT_SUCCESS);
case 'r':
return;
case 's':
- user_sectors = sectors = read_int(1, sectors, 63, 0,
- _("Number of sectors"));
+ user_sectors = g_sectors = read_int(1, g_sectors, 63, 0,
+ "Number of sectors");
if (dos_compatible_flag) {
- sector_offset = sectors;
- fprintf(stderr, _("Warning: setting "
- "sector offset for DOS "
- "compatiblity\n"));
+ sector_offset = g_sectors;
+ printf("Warning: setting sector offset for DOS "
+ "compatiblity\n");
}
update_units();
break;
@@ -5464,10 +2655,8 @@ xselect(void) {
write_table(); /* does not return */
break;
case 'y':
-#ifdef CONFIG_FEATURE_SUN_LABEL
- if (sun_label)
+ if (LABEL_IS_SUN)
sun_set_pcylcount();
-#endif
break;
default:
xmenu();
@@ -5477,7 +2666,8 @@ xselect(void) {
#endif /* ADVANCED mode */
static int
-is_ide_cdrom_or_tape(const char *device) {
+is_ide_cdrom_or_tape(const char *device)
+{
FILE *procf;
char buf[100];
struct stat statbuf;
@@ -5494,7 +2684,7 @@ is_ide_cdrom_or_tape(const char *device) {
return 0;
snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
- procf = fopen(buf, "r");
+ procf = fopen_for_read(buf);
if (procf != NULL && fgets(buf, sizeof(buf), procf))
is_ide = (!strncmp(buf, "cdrom", 5) ||
!strncmp(buf, "tape", 4));
@@ -5509,8 +2699,10 @@ is_ide_cdrom_or_tape(const char *device) {
return is_ide;
}
+
static void
-try(const char *device, int user_specified) {
+open_list_and_close(const char *device, int user_specified)
+{
int gb;
disk_device = device;
@@ -5519,303 +2711,235 @@ try(const char *device, int user_specified) {
if (!user_specified)
if (is_ide_cdrom_or_tape(device))
return;
- if ((fd = open(disk_device, type_open)) >= 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 (aix_label)
- return;
-#ifdef CONFIG_FEATURE_OSF_LABEL
- if (btrydev(device) < 0)
-#endif
- fprintf(stderr,
- _("Disk %s doesn't contain a valid "
- "partition table\n"), device);
- close(fd);
- } else {
- close(fd);
- list_table(0);
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
- if (!sun_label && partitions > 4)
- delete_partition(ext_index);
-#endif
- }
- } else {
+
+ /* Open disk_device, save file descriptor to dev_fd */
+ errno = 0;
+ gb = get_boot(TRY_ONLY);
+ if (gb > 0) { /* I/O error */
/* Ignore other errors, since we try IDE
and SCSI hard disks which may not be
installed on the system. */
- if (errno == EACCES) {
- fprintf(stderr, _("Cannot open %s\n"), device);
- return;
+ if (user_specified || errno == EACCES)
+ bb_perror_msg("can't open '%s'", device);
+ return;
+ }
+
+ if (gb < 0) { /* no DOS signature */
+ list_disk_geometry();
+ if (LABEL_IS_AIX)
+ goto ret;
+#if ENABLE_FEATURE_OSF_LABEL
+ if (bsd_trydev(device) < 0)
+#endif
+ printf("Disk %s doesn't contain a valid "
+ "partition table\n", device);
+ } else {
+ list_table(0);
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ if (!LABEL_IS_SUN && g_partitions > 4) {
+ delete_partition(ext_index);
}
+#endif
}
+ ret:
+ close_dev_fd();
}
/* 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) {
+list_devs_in_proc_partititons(void)
+{
FILE *procpt;
char line[100], ptname[100], devname[120], *s;
int ma, mi, sz;
- procpt = bb_wfopen(PROC_PARTITIONS, "r");
+ 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)
+ if (sscanf(line, " %d %d %d %[^\n ]",
+ &ma, &mi, &sz, ptname) != 4)
+ continue;
+ for (s = ptname; *s; s++)
continue;
- for (s = ptname; *s; s++);
if (isdigit(s[-1]))
continue;
sprintf(devname, "/dev/%s", ptname);
- try(devname, 0);
+ open_list_and_close(devname, 0);
}
-#ifdef CONFIG_FEATURE_CLEAN_UP
+#if ENABLE_FEATURE_CLEAN_UP
fclose(procpt);
#endif
}
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
+#if ENABLE_FEATURE_FDISK_WRITABLE
static void
-unknown_command(int c) {
- printf(_("%c: unknown command\n"), c);
+unknown_command(int c)
+{
+ printf("%c: unknown command\n", c);
}
#endif
-int fdisk_main(int argc, char **argv) {
- int c;
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
- int optl = 0;
-#endif
-#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
- int opts = 0;
-#endif
+int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int fdisk_main(int argc, char **argv)
+{
+ unsigned opt;
/*
- * Calls:
* fdisk -v
* fdisk -l [-b sectorsize] [-u] device ...
* fdisk -s [partition] ...
* fdisk [-b sectorsize] [-u] device
*
* Options -C, -H, -S set the geometry.
- *
*/
- while ((c = getopt(argc, argv, "b:C:H:lS:uvV"
-#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
- "s"
-#endif
- )) != -1) {
- switch (c) {
- case 'b':
- /* Ugly: this sector size is really per device,
- so cannot be combined with multiple disks,
- and te same goes for the C/H/S options.
- */
- sector_size = atoi(optarg);
- if (sector_size != 512 && sector_size != 1024 &&
- sector_size != 2048)
- bb_show_usage();
- sector_offset = 2;
- user_set_sector_size = 1;
- break;
- case 'C':
- user_cylinders = atoi(optarg);
- break;
- case 'H':
- user_heads = atoi(optarg);
- if (user_heads <= 0 || user_heads >= 256)
- user_heads = 0;
- break;
- case 'S':
- user_sectors = atoi(optarg);
- if (user_sectors <= 0 || user_sectors >= 64)
- user_sectors = 0;
- break;
- case 'l':
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
- optl = 1;
-#endif
- break;
-#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
- case 's':
- opts = 1;
- break;
-#endif
- case 'u':
- display_in_cyl_units = 0;
- break;
- case 'V':
- case 'v':
- printf("fdisk v" UTIL_LINUX_VERSION "\n");
- return 0;
- default:
+ INIT_G();
+
+ close_dev_fd(); /* needed: fd 3 must not stay closed */
+
+ opt_complementary = "b+:C+:H+:S+"; /* numeric params */
+ opt = getopt32(argv, "b:C:H:lS:u" USE_FEATURE_FDISK_BLKSIZE("s"),
+ &sector_size, &user_cylinders, &user_heads, &user_sectors);
+ 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.
+ */
+ if (sector_size != 512 && sector_size != 1024
+ && sector_size != 2048)
bb_show_usage();
- }
- }
-
-#if 0
- printf(_("This kernel finds the sector size itself - "
- "-b option ignored\n"));
-#else
- if (user_set_sector_size && argc-optind != 1)
- printf(_("Warning: the -b (set sector size) option should"
- " be used with one specified device\n"));
-#endif
-
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
- if (optl) {
+ sector_offset = 2;
+ user_set_sector_size = 1;
+ }
+ if (user_heads <= 0 || user_heads >= 256)
+ user_heads = 0;
+ if (user_sectors <= 0 || user_sectors >= 64)
+ user_sectors = 0;
+ if (opt & OPT_u)
+ display_in_cyl_units = 0; // -u
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ if (opt & OPT_l) {
nowarn = 1;
#endif
- type_open = O_RDONLY;
- if (argc > optind) {
- int k;
-#if __GNUC__
- /* avoid gcc warning:
- variable `k' might be clobbered by `longjmp' */
- (void)&k;
-#endif
+ if (*argv) {
listing = 1;
- for (k=optind; k<argc; k++)
- try(argv[k], 1);
+ do {
+ open_list_and_close(*argv, 1);
+ } while (*++argv);
} else {
- /* we no longer have default device names */
- /* but, we can use /proc/partitions instead */
- tryprocpt();
+ /* we don't have device names, */
+ /* use /proc/partitions instead */
+ list_devs_in_proc_partititons();
}
return 0;
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
+#if ENABLE_FEATURE_FDISK_WRITABLE
}
#endif
-#ifdef CONFIG_FEATURE_FDISK_BLKSIZE
- if (opts) {
- long size;
+#if ENABLE_FEATURE_FDISK_BLKSIZE
+ if (opt & OPT_s) {
int j;
nowarn = 1;
- type_open = O_RDONLY;
-
- opts = argc - optind;
- if (opts <= 0)
+ if (argc <= 0)
bb_show_usage();
-
- for (j = optind; j < argc; j++) {
- disk_device = argv[j];
- if ((fd = open(disk_device, type_open)) < 0)
- fdisk_fatal(unable_to_open);
- if (ioctl(fd, BLKGETSIZE, &size))
- fdisk_fatal(ioctl_error);
+ for (j = 0; j < argc; j++) {
+ unsigned long long size;
+ fd = xopen(argv[j], O_RDONLY);
+ size = bb_BLKGETSIZE_sectors(fd) / 2;
close(fd);
- if (opts == 1)
- printf("%ld\n", size/2);
+ if (argc == 1)
+ printf("%lld\n", size);
else
- printf("%s: %ld\n", argv[j], size/2);
+ printf("%s: %lld\n", argv[j], size);
}
return 0;
}
#endif
-#ifdef CONFIG_FEATURE_FDISK_WRITABLE
- if (argc-optind == 1)
- disk_device = argv[optind];
- else
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ if (argc != 1)
bb_show_usage();
- get_boot(fdisk);
+ disk_device = argv[0];
+ get_boot(OPEN_MAIN);
-#ifdef CONFIG_FEATURE_OSF_LABEL
- if (osf_label) {
+ if (LABEL_IS_OSF) {
/* OSF label, and no DOS label */
- printf(_("Detected an OSF/1 disklabel on %s, entering "
- "disklabel mode.\n"),
- disk_device);
- bselect();
- osf_label = 0;
+ 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? */
}
-#endif
while (1) {
- putchar('\n');
- c = tolower(read_char(_("Command (m for help): ")));
+ int c;
+ bb_putchar('\n');
+ c = tolower(read_nonempty("Command (m for help): "));
switch (c) {
case 'a':
- if (dos_label)
- toggle_active(get_partition(1, partitions));
-#ifdef CONFIG_FEATURE_SUN_LABEL
- else if (sun_label)
- toggle_sunflags(get_partition(1, partitions),
+ if (LABEL_IS_DOS)
+ toggle_active(get_partition(1, g_partitions));
+ else if (LABEL_IS_SUN)
+ toggle_sunflags(get_partition(1, g_partitions),
0x01);
-#endif
-#ifdef CONFIG_FEATURE_SGI_LABEL
- else if (sgi_label)
+ else if (LABEL_IS_SGI)
sgi_set_bootpartition(
- get_partition(1, partitions));
-#endif
+ get_partition(1, g_partitions));
else
unknown_command(c);
break;
case 'b':
-#ifdef CONFIG_FEATURE_SGI_LABEL
- if (sgi_label) {
- printf(_("\nThe current boot file is: %s\n"),
- sgi_get_bootfile());
- if (read_chars(_("Please enter the name of the "
- "new boot file: ")) == '\n')
- printf(_("Boot file unchanged\n"));
+ 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);
- } else
-#endif
-#ifdef CONFIG_FEATURE_OSF_LABEL
- bselect();
+ }
+#if ENABLE_FEATURE_OSF_LABEL
+ else
+ bsd_select();
#endif
break;
case 'c':
- if (dos_label)
+ if (LABEL_IS_DOS)
toggle_dos_compatibility_flag();
-#ifdef CONFIG_FEATURE_SUN_LABEL
- else if (sun_label)
- toggle_sunflags(get_partition(1, partitions),
+ else if (LABEL_IS_SUN)
+ toggle_sunflags(get_partition(1, g_partitions),
0x10);
-#endif
-#ifdef CONFIG_FEATURE_SGI_LABEL
- else if (sgi_label)
+ else if (LABEL_IS_SGI)
sgi_set_swappartition(
- get_partition(1, partitions));
-#endif
+ get_partition(1, g_partitions));
else
unknown_command(c);
break;
case 'd':
{
int j;
-#ifdef CONFIG_FEATURE_SGI_LABEL
/* 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 (!sgi_label) {
- j = get_existing_partition(1, partitions);
+ if (!LABEL_IS_SGI) {
+ j = get_existing_partition(1, g_partitions);
} else {
- j = get_partition(1, partitions);
+ j = get_partition(1, g_partitions);
}
-#else
- j = get_existing_partition(1, partitions);
-#endif
if (j >= 0)
delete_partition(j);
}
break;
case 'i':
-#ifdef CONFIG_FEATURE_SGI_LABEL
- if (sgi_label)
+ if (LABEL_IS_SGI)
create_sgiinfo();
else
-#endif
unknown_command(c);
case 'l':
list_types(get_sys_types());
@@ -5833,11 +2957,12 @@ int fdisk_main(int argc, char **argv) {
list_table(0);
break;
case 'q':
- close(fd);
- printf("\n");
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close_dev_fd();
+ bb_putchar('\n');
return 0;
case 's':
-#ifdef CONFIG_FEATURE_SUN_LABEL
+#if ENABLE_FEATURE_SUN_LABEL
create_sunlabel();
#endif
break;
@@ -5853,16 +2978,12 @@ int fdisk_main(int argc, char **argv) {
case 'w':
write_table(); /* does not return */
break;
-#ifdef CONFIG_FEATURE_FDISK_ADVANCED
+#if ENABLE_FEATURE_FDISK_ADVANCED
case 'x':
-#ifdef CONFIG_FEATURE_SGI_LABEL
- if (sgi_label) {
- fprintf(stderr,
- _("\n\tSorry, no experts menu for SGI "
- "partition tables available.\n\n"));
+ if (LABEL_IS_SGI) {
+ printf("\n\tSorry, no experts menu for SGI "
+ "partition tables available\n\n");
} else
-#endif
-
xselect();
break;
#endif
@@ -5872,5 +2993,5 @@ int fdisk_main(int argc, char **argv) {
}
}
return 0;
-#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
+#endif /* FEATURE_FDISK_WRITABLE */
}
diff --git a/release/src/router/busybox/util-linux/fdisk_aix.c b/release/src/router/busybox/util-linux/fdisk_aix.c
new file mode 100644
index 00000000..2c0d2a6a
--- /dev/null
+++ b/release/src/router/busybox/util-linux/fdisk_aix.c
@@ -0,0 +1,73 @@
+#if ENABLE_FEATURE_AIX_LABEL
+/*
+ * Copyright (C) Andreas Neuper, Sep 1998.
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+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 smallint aix_other_endian; /* bool */
+static smallint aix_volumes = 1; /* max 15 */
+
+/*
+ * 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;
+ g_partitions = 1016;
+ aix_volumes = 15;
+ aix_info();
+ /*aix_nolabel();*/ /* %% */
+ /*aix_label = 1;*/ /* %% */
+ return 1;
+}
+#endif /* AIX_LABEL */
diff --git a/release/src/router/busybox/util-linux/fdisk_osf.c b/release/src/router/busybox/util-linux/fdisk_osf.c
new file mode 100644
index 00000000..ea5cd3c1
--- /dev/null
+++ b/release/src/router/busybox/util-linux/fdisk_osf.c
@@ -0,0 +1,1052 @@
+/*
+ * 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.
+ */
+
+#if ENABLE_FEATURE_OSF_LABEL
+
+#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
+};
+
+
+/*
+ * 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
+};
+
+
+/*
+ * 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()
+*/
+
+#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) {
+ bb_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':
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close_dev_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) {
+ static const int d_masks[] = { BSD_D_REMOVABLE, BSD_D_ECC, BSD_D_BADSECT };
+
+#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 < ARRAY_SIZE(xbsd_dktypenames)-1)
+ 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: ");
+ print_flags_separated(d_masks, "removable\0""ecc\0""badsect\0", lp->d_flags, " ");
+ bb_putchar('\n');
+ /* 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 < ARRAY_SIZE(xbsd_fstypes)-1)
+ 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;
+ }
+ bb_putchar('\n');
+ }
+ }
+}
+
+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;
+ }
+ return 0;
+ }
+ 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_or_warn(path, O_RDONLY);
+ if (fdb < 0) {
+ return 0;
+ }
+ if (full_read(fdb, ptr, size) < 0) {
+ bb_simple_perror_msg(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
+
+ seek_sector(sector);
+ xwrite(dev_fd, disklabelbuffer, BSD_BBSIZE);
+
+#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 = g_sectors; /* sectors/track */
+ d->d_ntracks = g_heads; /* tracks/cylinder (heads) */
+ d->d_ncylinders = g_cylinders;
+ d->d_secpercyl = g_sectors * g_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
+
+ seek_sector(sector);
+ if (BSD_BBSIZE != full_read(dev_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);
+ seek_sector(0);
+ xwrite(dev_fd, disklabelbuffer, BSD_BBSIZE);
+#else
+ seek_sector(sector);
+ lseek(dev_fd, BSD_LABELOFFSET, SEEK_CUR);
+ xwrite(dev_fd, d, sizeof(*d));
+#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, g_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/release/src/router/busybox/util-linux/fdisk_sgi.c b/release/src/router/busybox/util-linux/fdisk_sgi.c
new file mode 100644
index 00000000..51cf30c9
--- /dev/null
+++ b/release/src/router/busybox/util-linux/fdisk_sgi.c
@@ -0,0 +1,886 @@
+/*
+ * Copyright (C) Andreas Neuper, Sep 1998.
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#if ENABLE_FEATURE_SGI_LABEL
+
+#define SGI_DEBUG 0
+
+#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 smallint sgi_other_endian; /* bool */
+static smallint sgi_volumes = 1; /* max 15 */
+
+/*
+ * 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;
+ g_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, g_heads, g_sectors, g_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, g_heads, g_sectors, g_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 < g_partitions; i++) {
+ if (sgi_get_num_sectors(i) || SGI_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 g_heads * g_sectors * g_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);
+
+ write_sector(0, sgilabel);
+ 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);
+ write_sector(infostartblock, info);
+ 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 (SGI_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 (SGI_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 (SGI_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 (SGI_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 (SGI_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 < g_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 < g_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 (g_heads * g_sectors * 5 < sgi_get_lastblock())
+ sgi_set_partition(n, 0, g_heads * g_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 = BB_LITTLE_ENDIAN;
+ res = ioctl(dev_fd, BLKGETSIZE, &longsectors);
+ if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
+ g_heads = geometry.heads;
+ g_sectors = geometry.sectors;
+ if (res == 0) {
+ /* the get device size ioctl was successful */
+ g_cylinders = longsectors / (g_heads * g_sectors);
+ g_cylinders /= sec_fac;
+ } else {
+ /* otherwise print error and use truncated version */
+ g_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, g_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 (SGI_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;
+ g_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/release/src/router/busybox/util-linux/fdisk_sun.c b/release/src/router/busybox/util-linux/fdisk_sun.c
new file mode 100644
index 00000000..9cdf869e
--- /dev/null
+++ b/release/src/router/busybox/util-linux/fdisk_sun.c
@@ -0,0 +1,728 @@
+/*
+ * fdisk_sun.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
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#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
+
+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(dev_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 / (g_heads * g_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 {
+ g_heads = SUN_SSWAP16(sunlabel->ntrks);
+ g_cylinders = SUN_SSWAP16(sunlabel->ncyl);
+ g_sectors = SUN_SSWAP16(sunlabel->nsect);
+ }
+ update_units();
+ current_label_type = LABEL_SUN;
+ g_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(dev_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_for_read("/proc/scsi/scsi");
+ 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 < ARRAY_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 ndiv;
+ 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) {
+ unsigned i;
+ puts("Drive type\n"
+ " ? auto configure\n"
+ " 0 custom (with hardware detected defaults)");
+ for (i = 0; i < ARRAY_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' + ARRAY_SIZE(sun_drives)) {
+ p = sun_drives + c - 'a';
+ break;
+ }
+ if (c >= 'A' && c < 'A' + ARRAY_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(dev_fd, HDIO_GETGEO, &geometry)) {
+ g_heads = geometry.heads;
+ g_sectors = geometry.sectors;
+ g_cylinders = geometry.cylinders;
+ } else {
+ g_heads = 0;
+ g_sectors = 0;
+ g_cylinders = 0;
+ }
+ if (floppy) {
+ sunlabel->nacyl = 0;
+ sunlabel->pcylcount = SUN_SSWAP16(g_cylinders);
+ sunlabel->rspeed = SUN_SSWAP16(300);
+ sunlabel->ilfact = SUN_SSWAP16(1);
+ sunlabel->sparecyl = 0;
+ } else {
+ g_heads = read_int(1, g_heads, 1024, 0, "Heads");
+ g_sectors = read_int(1, g_sectors, 1024, 0, "Sectors/track");
+ if (g_cylinders)
+ g_cylinders = read_int(1, g_cylinders - 2, 65535, 0, "Cylinders");
+ else
+ g_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, g_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, g_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);
+ g_cylinders = p->ncyl;
+ g_heads = p->ntrks;
+ g_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"),
+ g_cylinders, SUN_SSWAP16(sunlabel->nacyl), g_heads, g_sectors);
+
+ sunlabel->ntrks = SUN_SSWAP16(g_heads);
+ sunlabel->nsect = SUN_SSWAP16(g_sectors);
+ sunlabel->ncyl = SUN_SSWAP16(g_cylinders);
+ if (floppy)
+ set_sun_partition(0, 0, g_cylinders * g_heads * g_sectors, LINUX_NATIVE);
+ else {
+ if (g_cylinders * g_heads * g_sectors >= 150 * 2048) {
+ ndiv = g_cylinders - (50 * 2048 / (g_heads * g_sectors)); /* 50M swap */
+ } else
+ ndiv = g_cylinders * 2 / 3;
+ set_sun_partition(0, 0, ndiv * g_heads * g_sectors, LINUX_NATIVE);
+ set_sun_partition(1, ndiv * g_heads * g_sectors, g_cylinders * g_heads * g_sectors, LINUX_SWAP);
+ sunlabel->infos[1].flags |= 0x01; /* Not mountable */
+ }
+ set_sun_partition(2, 0, g_cylinders * g_heads * g_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 = g_cylinders * g_heads * g_sectors;
+ for (i = 0; i < g_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) * g_heads * g_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] % (g_heads * g_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, 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 = g_cylinders * g_heads * g_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 + g_heads * g_sectors - 1) / (g_heads * g_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 < g_partitions; i++)
+ if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
+ break;
+ if (i < g_partitions && !whole_disk) {
+ if (n == 2 && !first) {
+ whole_disk = 1;
+ break;
+ }
+ printf("Sector %d is already allocated\n", first);
+ } else
+ break;
+ }
+ stop = g_cylinders * g_heads * g_sectors;
+ stop2 = stop;
+ for (i = 0; i < g_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)) == g_heads * g_sectors * g_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, g_heads, g_sectors, SUN_SSWAP16(sunlabel->rspeed),
+ g_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, g_heads, g_sectors, g_cylinders,
+ str_units(PLURAL), units_per_sector);
+
+ printf("%*s Flag Start End Blocks Id System\n",
+ w + 1, "Device");
+ for (i = 0; i < g_partitions; i++) {
+ if (sunlabel->partitions[i].num_sectors) {
+ uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * g_heads * g_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), g_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;
+ write_sector(0, sunlabel);
+}
+#endif /* SUN_LABEL */
diff --git a/release/src/router/busybox/util-linux/findfs.c b/release/src/router/busybox/util-linux/findfs.c
new file mode 100644
index 00000000..5b64399a
--- /dev/null
+++ b/release/src/router/busybox/util-linux/findfs.c
@@ -0,0 +1,38 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Support functions for mounting devices by label/uuid
+ *
+ * Copyright (C) 2006 by Jason Schoon <floydpink@gmail.com>
+ * Some portions cribbed from e2fsprogs, util-linux, dosfstools
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "volume_id.h"
+
+int findfs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int findfs_main(int argc, char **argv)
+{
+ char *tmp = NULL;
+
+ if (argc != 2)
+ bb_show_usage();
+
+ if (!strncmp(argv[1], "LABEL=", 6))
+ tmp = get_devname_from_label(argv[1] + 6);
+ else if (!strncmp(argv[1], "UUID=", 5))
+ tmp = get_devname_from_uuid(argv[1] + 5);
+ else if (!strncmp(argv[1], "/dev/", 5)) {
+ /* Just pass a device name right through. This might aid in some scripts
+ being able to call this unconditionally */
+ tmp = argv[1];
+ } else
+ bb_show_usage();
+
+ if (tmp) {
+ puts(tmp);
+ return 0;
+ }
+ return 1;
+}
diff --git a/release/src/router/busybox/util-linux/freeramdisk.c b/release/src/router/busybox/util-linux/freeramdisk.c
index af00c667..bde6afc0 100644
--- a/release/src/router/busybox/util-linux/freeramdisk.c
+++ b/release/src/router/busybox/util-linux/freeramdisk.c
@@ -1,68 +1,33 @@
/* vi: set sw=4 ts=4: */
/*
- * freeramdisk implementation for busybox
+ * 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>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <stdlib.h>
-#include "busybox.h"
+#include "libbb.h"
+/* From <linux/fd.h> */
+#define FDFLUSH _IO(2,0x4b)
-/* From linux/fs.h */
-#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
-
-extern int
-freeramdisk_main(int argc, char **argv)
+int freeramdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int freeramdisk_main(int argc, char **argv)
{
- int result;
int fd;
- if (argc != 2) {
- bb_show_usage();
- }
+ if (argc != 2) bb_show_usage();
- fd = bb_xopen(argv[1], O_RDWR);
-
- result = ioctl(fd, BLKFLSBUF);
-#ifdef CONFIG_FEATURE_CLEAN_UP
- close(fd);
-#endif
- if (result < 0) {
- bb_perror_msg_and_die("failed ioctl on %s", argv[1]);
- }
+ fd = xopen(argv[1], O_RDWR);
- /* Don't bother closing. Exit does
- * that, so we can save a few bytes */
- return EXIT_SUCCESS;
-}
+ // Act like freeramdisk, fdflush, or both depending on configuration.
+ ioctl_or_perror_and_die(fd, (ENABLE_FREERAMDISK && applet_name[1]=='r')
+ || !ENABLE_FDFLUSH ? BLKFLSBUF : FDFLUSH, NULL, "%s", argv[1]);
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+ if (ENABLE_FEATURE_CLEAN_UP) close(fd);
+ return EXIT_SUCCESS;
+}
diff --git a/release/src/router/busybox/util-linux/fsck_minix.c b/release/src/router/busybox/util-linux/fsck_minix.c
index 3a691476..78a7c826 100644
--- a/release/src/router/busybox/util-linux/fsck_minix.c
+++ b/release/src/router/busybox/util-linux/fsck_minix.c
@@ -2,12 +2,13 @@
/*
* fsck.c - a file system consistency checker for Linux.
*
- * (C) 1991, 1992 Linus Torvalds. This file may be redistributed
- * as per the GNU copyleft.
+ * (C) 1991, 1992 Linus Torvalds.
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
/*
- * 09.11.91 - made the first rudimetary functions
+ * 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.
@@ -28,7 +29,7 @@
* 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
+ * superblock information
*
* Sat Oct 9 11:17:11 1993, faith@cs.unc.edu: make exit status conform
* to that required by fsutil
@@ -49,21 +50,21 @@
* 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
+ * 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 systemindependent.
+ * 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
+ * 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>
+ * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
* - added Native Language Support
*
*
@@ -73,241 +74,267 @@
* unless you can be sure nobody is writing to it (and remember that the
* kernel can write to it when it searches for files).
*
- * Usuage: fsck [-larvsm] device
+ * 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
+ * -s for superblock 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 :-).
+ * enforced (but it's not much fun on a character device :-).
*/
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <termios.h>
#include <mntent.h>
-#include <sys/param.h>
-#include "busybox.h"
-
-static const int MINIX_ROOT_INO = 1;
-static const int MINIX_LINK_MAX = 250;
-static const int MINIX2_LINK_MAX = 65530;
-
-static const int MINIX_I_MAP_SLOTS = 8;
-static const int MINIX_Z_MAP_SLOTS = 64;
-static const int MINIX_SUPER_MAGIC = 0x137F; /* original minix fs */
-static const int MINIX_SUPER_MAGIC2 = 0x138F; /* minix fs, 30 char names */
-static const int MINIX2_SUPER_MAGIC = 0x2468; /* minix V2 fs */
-static const int MINIX2_SUPER_MAGIC2 = 0x2478; /* minix V2 fs, 30 char names */
-static const int MINIX_VALID_FS = 0x0001; /* Clean fs. */
-static const int MINIX_ERROR_FS = 0x0002; /* fs has errors. */
-
-#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
-#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
+#include "libbb.h"
+#include "minix.h"
-static const int MINIX_V1 = 0x0001; /* original minix fs */
-static const int MINIX_V2 = 0x0002; /* minix V2 fs */
-
-#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version
-
-/*
- * This is the original minix inode layout on disk.
- * Note the 8-bit gid and atime and ctime.
- */
-struct minix_inode {
- u_int16_t i_mode;
- u_int16_t i_uid;
- u_int32_t i_size;
- u_int32_t i_time;
- u_int8_t i_gid;
- u_int8_t i_nlinks;
- u_int16_t i_zone[9];
-};
+#ifndef BLKGETSIZE
+#define BLKGETSIZE _IO(0x12,96) /* return device size */
+#endif
-/*
- * 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 {
- u_int16_t i_mode;
- u_int16_t i_nlinks;
- u_int16_t i_uid;
- u_int16_t i_gid;
- u_int32_t i_size;
- u_int32_t i_atime;
- u_int32_t i_mtime;
- u_int32_t i_ctime;
- u_int32_t i_zone[10];
+struct BUG_bad_inode_size {
+ char BUG_bad_inode1_size[(INODE_SIZE1 * MINIX1_INODES_PER_BLOCK != BLOCK_SIZE) ? -1 : 1];
+#if ENABLE_FEATURE_MINIX2
+ char BUG_bad_inode2_size[(INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) ? -1 : 1];
+#endif
};
-/*
- * minix super-block data on disk
- */
-struct minix_super_block {
- u_int16_t s_ninodes;
- u_int16_t s_nzones;
- u_int16_t s_imap_blocks;
- u_int16_t s_zmap_blocks;
- u_int16_t s_firstdatazone;
- u_int16_t s_log_zone_size;
- u_int32_t s_max_size;
- u_int16_t s_magic;
- u_int16_t s_state;
- u_int32_t s_zones;
+enum {
+#ifdef UNUSED
+ 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 */
+#endif
+ MINIX_NAME_MAX = 255, /* # chars in a file name */
};
-struct minix_dir_entry {
- u_int16_t inode;
- char name[0];
-};
-#define BLOCK_SIZE_BITS 10
-#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
+#if !ENABLE_FEATURE_MINIX2
+enum { version2 = 0 };
+#endif
-#define NAME_MAX 255 /* # chars in a file name */
+enum { MAX_DEPTH = 32 };
-#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
+enum { dev_fd = 3 };
-#ifndef BLKGETSIZE
-#define BLKGETSIZE _IO(0x12,96) /* return device size */
+struct globals {
+#if ENABLE_FEATURE_MINIX2
+ smallint version2;
#endif
+ smallint changed; /* is filesystem modified? */
+ smallint errors_uncorrected; /* flag if some error was not corrected */
+ smallint termios_set;
+ smallint dirsize;
+ smallint namelen;
+ const char *device_name;
+ int directory, regular, blockdev, chardev, links, symlinks, total;
+ char *inode_buffer;
+
+ char *inode_map;
+ char *zone_map;
+
+ unsigned char *inode_count;
+ unsigned char *zone_count;
+
+ /* File-name data */
+ int name_depth;
+ char *name_component[MAX_DEPTH+1];
+
+ /* Bigger stuff */
+ struct termios sv_termios;
+ char superblock_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];
+
+ /* File-name data */
+ char current_name[MAX_DEPTH * MINIX_NAME_MAX];
+};
-#ifndef __linux__
-#define volatile
+#define G (*ptr_to_globals)
+#if ENABLE_FEATURE_MINIX2
+#define version2 (G.version2 )
#endif
+#define changed (G.changed )
+#define errors_uncorrected (G.errors_uncorrected )
+#define termios_set (G.termios_set )
+#define dirsize (G.dirsize )
+#define namelen (G.namelen )
+#define device_name (G.device_name )
+#define directory (G.directory )
+#define regular (G.regular )
+#define blockdev (G.blockdev )
+#define chardev (G.chardev )
+#define links (G.links )
+#define symlinks (G.symlinks )
+#define total (G.total )
+#define inode_buffer (G.inode_buffer )
+#define inode_map (G.inode_map )
+#define zone_map (G.zone_map )
+#define inode_count (G.inode_count )
+#define zone_count (G.zone_count )
+#define name_depth (G.name_depth )
+#define name_component (G.name_component )
+#define sv_termios (G.sv_termios )
+#define superblock_buffer (G.superblock_buffer )
+#define add_zone_ind_blk (G.add_zone_ind_blk )
+#define add_zone_dind_blk (G.add_zone_dind_blk )
+#define add_zone_tind_blk (G.add_zone_tind_blk )
+#define check_file_blk (G.check_file_blk )
+#define current_name (G.current_name )
+#define INIT_G() do { \
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+ dirsize = 16; \
+ namelen = 14; \
+ current_name[0] = '/'; \
+ /*current_name[1] = '\0';*/ \
+ name_component[0] = &current_name[0]; \
+} while (0)
+
+
+#define OPTION_STR "larvsmf"
+enum {
+ OPT_l = (1 << 0),
+ OPT_a = (1 << 1),
+ OPT_r = (1 << 2),
+ OPT_v = (1 << 3),
+ OPT_s = (1 << 4),
+ OPT_w = (1 << 5),
+ OPT_f = (1 << 6),
+};
+#define OPT_list (option_mask32 & OPT_l)
+#define OPT_automatic (option_mask32 & OPT_a)
+#define OPT_repair (option_mask32 & OPT_r)
+#define OPT_verbose (option_mask32 & OPT_v)
+#define OPT_show (option_mask32 & OPT_s)
+#define OPT_warn_mode (option_mask32 & OPT_w)
+#define OPT_force (option_mask32 & OPT_f)
+/* non-automatic repairs requested? */
+#define OPT_manual ((option_mask32 & (OPT_a|OPT_r)) == OPT_r)
+
+
+#define Inode1 (((struct minix1_inode *) inode_buffer)-1)
+#define Inode2 (((struct minix2_inode *) inode_buffer)-1)
-static const int ROOT_INO = 1;
+#define Super (*(struct minix_superblock *)(superblock_buffer))
-#define UPPER(size,n) ((size+((n)-1))/(n))
-#define INODE_SIZE (sizeof(struct minix_inode))
-#ifdef CONFIG_FEATURE_MINIX2
-#define INODE_SIZE2 (sizeof(struct minix2_inode))
-#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
- : MINIX_INODES_PER_BLOCK))
+#if ENABLE_FEATURE_MINIX2
+# define ZONES ((unsigned)(version2 ? Super.s_zones : Super.s_nzones))
#else
-#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK))
+# define ZONES ((unsigned)(Super.s_nzones))
#endif
-#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
-
-#define BITS_PER_BLOCK (BLOCK_SIZE<<3)
-
-static char *program_version = "1.2 - 11/11/96";
-static char *device_name = NULL;
-static int IN;
-static int repair = 0, automatic = 0, verbose = 0, list = 0, show =
- 0, warn_mode = 0, force = 0;
-static int directory = 0, regular = 0, blockdev = 0, chardev = 0, links =
- 0, symlinks = 0, total = 0;
-
-static int changed = 0; /* flags if the filesystem has been changed */
-static int errors_uncorrected = 0; /* flag if some error was not corrected */
-static int dirsize = 16;
-static int namelen = 14;
-static int version2 = 0;
-static struct termios termios;
-static int termios_set = 0;
-
-/* File-name data */
-static const int MAX_DEPTH = 32;
-static int name_depth = 0;
-// static char name_list[MAX_DEPTH][BUFSIZ + 1];
-static char **name_list = NULL;
-
-static char *inode_buffer = NULL;
-
-#define Inode (((struct minix_inode *) inode_buffer)-1)
-#define Inode2 (((struct minix2_inode *) inode_buffer)-1)
-static char super_block_buffer[BLOCK_SIZE];
+#define 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 ALWAYS_INLINE unsigned div_roundup(unsigned size, unsigned n)
+{
+ return (size + n-1) / n;
+}
-#define Super (*(struct minix_super_block *)super_block_buffer)
-#define INODES ((unsigned long)Super.s_ninodes)
-#ifdef CONFIG_FEATURE_MINIX2
-#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones))
+#if !ENABLE_FEATURE_MINIX2
+#define INODE_BLOCKS div_roundup(INODES, MINIX1_INODES_PER_BLOCK)
#else
-#define ZONES ((unsigned long)(Super.s_nzones))
-#endif
-#define IMAPS ((unsigned long)Super.s_imap_blocks)
-#define ZMAPS ((unsigned long)Super.s_zmap_blocks)
-#define FIRSTZONE ((unsigned long)Super.s_firstdatazone)
-#define ZONESIZE ((unsigned long)Super.s_log_zone_size)
-#define MAXSIZE ((unsigned long)Super.s_max_size)
-#define MAGIC (Super.s_magic)
-#define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS)
-
-static char *inode_map;
-static char *zone_map;
-
-static unsigned char *inode_count = NULL;
-static unsigned char *zone_count = NULL;
-
-static void recursive_check(unsigned int ino);
-#ifdef CONFIG_FEATURE_MINIX2
-static void recursive_check2(unsigned int ino);
+#define INODE_BLOCKS div_roundup(INODES, \
+ (version2 ? MINIX2_INODES_PER_BLOCK : MINIX1_INODES_PER_BLOCK))
#endif
-static inline int bit(char * a,unsigned int i)
+#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
+#define NORM_FIRSTZONE (2 + IMAPS + 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))) != 0;
+ return (a[i >> 3] & (1<<(i & 7)));
}
-#define inode_in_use(x) (bit(inode_map,(x)))
-#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1))
-#define mark_inode(x) (setbit(inode_map,(x)),changed=1)
-#define unmark_inode(x) (clrbit(inode_map,(x)),changed=1)
+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))
-#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1),changed=1)
-#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1),changed=1)
-static void leave(int) __attribute__ ((noreturn));
-static void leave(int status)
+static void recursive_check(unsigned ino);
+#if ENABLE_FEATURE_MINIX2
+static void recursive_check2(unsigned ino);
+#endif
+
+static void die(const char *str) NORETURN;
+static void die(const char *str)
{
if (termios_set)
- tcsetattr(0, TCSANOW, &termios);
- exit(status);
+ tcsetattr_stdin_TCSANOW(&sv_termios);
+ bb_error_msg_and_die("%s", str);
}
-static void die(const char *str)
+static void push_filename(const char *name)
{
- bb_error_msg("%s", str);
- leave(8);
+ // /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++;
}
-/*
- * This simply goes through the file-name data and prints out the
- * current file.
- */
-static void print_current_name(void)
+static void pop_filename(void)
{
- int i = 0;
-
- while (i < name_depth)
- printf("/%.*s", namelen, name_list[i++]);
- if (i == 0)
- printf("/");
+ 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) {
- printf("\n");
+ if (!OPT_repair) {
+ bb_putchar('\n');
errors_uncorrected = 1;
return 0;
}
- if (automatic) {
- printf("\n");
+ if (OPT_automatic) {
+ bb_putchar('\n');
if (!def)
errors_uncorrected = 1;
return def;
@@ -315,7 +342,8 @@ static int ask(const char *string, int def)
printf(def ? "%s (y/n)? " : "%s (n/y)? ", string);
for (;;) {
fflush(stdout);
- if ((c = getchar()) == EOF) {
+ c = getchar();
+ if (c == EOF) {
if (!def)
errors_uncorrected = 1;
return def;
@@ -350,8 +378,9 @@ static void check_mount(void)
struct mntent *mnt;
int cont;
int fd;
-
- if ((f = setmntent(MOUNTED, "r")) == NULL)
+//XXX:FIXME use find_mount_point()
+ f = setmntent(MOUNTED, "r");
+ if (f == NULL)
return;
while ((mnt = getmntent(f)) != NULL)
if (strcmp(device_name, mnt->mnt_fsname) == 0)
@@ -368,19 +397,16 @@ static void check_mount(void)
fd = open(MOUNTED, O_RDWR);
if (fd < 0 && errno == EROFS)
return;
- else
- close(fd);
+ close(fd);
- printf("%s is mounted. ", device_name);
+ printf("%s is mounted. ", device_name);
+ cont = 0;
if (isatty(0) && isatty(1))
cont = ask("Do you really want to continue", 0);
- else
- cont = 0;
if (!cont) {
- printf("check aborted.\n");
- exit(0);
+ printf("Check aborted\n");
+ exit(EXIT_SUCCESS);
}
- return;
}
/*
@@ -389,18 +415,18 @@ static void check_mount(void)
* if an error was corrected, and returns the zone (0 for no zone
* or a bad zone-number).
*/
-static int check_zone_nr(unsigned short *nr, int *corrected)
+static int check_zone_nr2(uint32_t *nr, smallint *corrected)
{
+ const char *msg;
if (!*nr)
return 0;
if (*nr < FIRSTZONE)
- printf("Zone nr < FIRSTZONE in file `");
+ msg = "< FIRSTZONE";
else if (*nr >= ZONES)
- printf("Zone nr >= ZONES in file `");
+ msg = ">= ZONES";
else
return *nr;
- print_current_name();
- printf("'.");
+ printf("Zone nr %s in file '%s'. ", msg, current_name);
if (ask("Remove block", 1)) {
*nr = 0;
*corrected = 1;
@@ -408,55 +434,36 @@ static int check_zone_nr(unsigned short *nr, int *corrected)
return 0;
}
-#ifdef CONFIG_FEATURE_MINIX2
-static int check_zone_nr2(unsigned int *nr, int *corrected)
+static int check_zone_nr(uint16_t *nr, smallint *corrected)
{
- if (!*nr)
- return 0;
- if (*nr < FIRSTZONE)
- printf("Zone nr < FIRSTZONE in file `");
- else if (*nr >= ZONES)
- printf("Zone nr >= ZONES in file `");
- else
- return *nr;
- print_current_name();
- printf("'.");
- if (ask("Remove block", 1)) {
- *nr = 0;
- *corrected = 1;
- }
- return 0;
+ uint32_t nr32 = *nr;
+ int r = check_zone_nr2(&nr32, corrected);
+ *nr = (uint16_t)nr32;
+ return r;
}
-#endif
/*
* read-block reads block nr into the buffer at addr.
*/
-static void read_block(unsigned int nr, char *addr)
+static void read_block(unsigned nr, void *addr)
{
if (!nr) {
memset(addr, 0, BLOCK_SIZE);
return;
}
- if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET)) {
- printf("Read error: unable to seek to block in file '");
- print_current_name();
- printf("'\n");
- memset(addr, 0, BLOCK_SIZE);
+ xlseek(dev_fd, BLOCK_SIZE * nr, SEEK_SET);
+ if (BLOCK_SIZE != full_read(dev_fd, addr, BLOCK_SIZE)) {
+ printf("%s: bad block %u in file '%s'\n",
+ bb_msg_read_error, nr, current_name);
errors_uncorrected = 1;
- } else if (BLOCK_SIZE != read(IN, addr, BLOCK_SIZE)) {
- printf("Read error: bad block in file '");
- print_current_name();
- printf("'\n");
memset(addr, 0, BLOCK_SIZE);
- errors_uncorrected = 1;
}
}
/*
* write_block writes block nr to disk.
*/
-static void write_block(unsigned int nr, char *addr)
+static void write_block(unsigned nr, void *addr)
{
if (!nr)
return;
@@ -466,145 +473,119 @@ static void write_block(unsigned int nr, char *addr)
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("Write error: bad block in file '");
- print_current_name();
- printf("'\n");
+ xlseek(dev_fd, BLOCK_SIZE * nr, SEEK_SET);
+ if (BLOCK_SIZE != full_write(dev_fd, addr, BLOCK_SIZE)) {
+ printf("%s: bad block %u in file '%s'\n",
+ bb_msg_write_error, nr, current_name);
errors_uncorrected = 1;
}
}
/*
- * map-block calculates the absolute block nr of a block in a file.
+ * 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 minix_inode *inode, unsigned int blknr)
+static int map_block(struct minix1_inode *inode, unsigned blknr)
{
- unsigned short ind[BLOCK_SIZE >> 1];
- unsigned short dind[BLOCK_SIZE >> 1];
- int blk_chg, block, result;
+ uint16_t ind[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;
+ goto common;
}
blknr -= 512;
block = check_zone_nr(inode->i_zone + 8, &changed);
- read_block(block, (char *) dind);
+ read_block(block, ind); /* double indirect */
blk_chg = 0;
- result = check_zone_nr(dind + (blknr / 512), &blk_chg);
+ result = check_zone_nr(&ind[blknr / 512], &blk_chg);
if (blk_chg)
- write_block(block, (char *) dind);
+ write_block(block, ind);
block = result;
- read_block(block, (char *) ind);
+ common:
+ read_block(block, ind);
blk_chg = 0;
- result = check_zone_nr(ind + (blknr % 512), &blk_chg);
+ result = check_zone_nr(&ind[blknr % 512], &blk_chg);
if (blk_chg)
- write_block(block, (char *) ind);
+ write_block(block, ind);
return result;
}
-#ifdef CONFIG_FEATURE_MINIX2
-static int map_block2(struct minix2_inode *inode, unsigned int blknr)
+#if ENABLE_FEATURE_MINIX2
+static int map_block2(struct minix2_inode *inode, unsigned blknr)
{
- unsigned int ind[BLOCK_SIZE >> 2];
- unsigned int dind[BLOCK_SIZE >> 2];
- unsigned int tind[BLOCK_SIZE >> 2];
- int blk_chg, block, result;
+ uint32_t ind[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;
+ goto common2;
}
blknr -= 256;
- if (blknr >= 256 * 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;
+ goto common1;
}
blknr -= 256 * 256;
block = check_zone_nr2(inode->i_zone + 9, &changed);
- read_block(block, (char *) tind);
+ read_block(block, ind); /* triple indirect */
blk_chg = 0;
- result = check_zone_nr2(tind + blknr / (256 * 256), &blk_chg);
+ result = check_zone_nr2(&ind[blknr / (256 * 256)], &blk_chg);
if (blk_chg)
- write_block(block, (char *) tind);
+ write_block(block, ind);
block = result;
- read_block(block, (char *) dind);
+ common1:
+ read_block(block, ind); /* double indirect */
blk_chg = 0;
- result = check_zone_nr2(dind + (blknr / 256) % 256, &blk_chg);
+ result = check_zone_nr2(&ind[(blknr / 256) % 256], &blk_chg);
if (blk_chg)
- write_block(block, (char *) dind);
+ write_block(block, ind);
block = result;
- read_block(block, (char *) ind);
+ common2:
+ read_block(block, ind);
blk_chg = 0;
- result = check_zone_nr2(ind + blknr % 256, &blk_chg);
+ result = check_zone_nr2(&ind[blknr % 256], &blk_chg);
if (blk_chg)
- write_block(block, (char *) ind);
+ write_block(block, ind);
return result;
}
#endif
-static void write_super_block(void)
+static void write_superblock(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;
- if (errors_uncorrected)
- Super.s_state |= MINIX_ERROR_FS;
- else
+ 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, super_block_buffer, BLOCK_SIZE))
- die("unable to write super-block");
-
- return;
+ xlseek(dev_fd, BLOCK_SIZE, SEEK_SET);
+ if (BLOCK_SIZE != full_write(dev_fd, superblock_buffer, BLOCK_SIZE))
+ die("cannot write superblock");
}
static void write_tables(void)
{
- write_super_block();
-
- if (IMAPS * BLOCK_SIZE != write(IN, inode_map, IMAPS * BLOCK_SIZE))
- die("Unable to write inode map");
- if (ZMAPS * BLOCK_SIZE != write(IN, zone_map, ZMAPS * BLOCK_SIZE))
- die("Unable to write zone map");
- if (INODE_BUFFER_SIZE != write(IN, inode_buffer, INODE_BUFFER_SIZE))
- die("Unable to write inodes");
+ write_superblock();
+
+ if (IMAPS * BLOCK_SIZE != write(dev_fd, inode_map, IMAPS * BLOCK_SIZE))
+ die("cannot write inode map");
+ if (ZMAPS * BLOCK_SIZE != write(dev_fd, zone_map, ZMAPS * BLOCK_SIZE))
+ die("cannot write zone map");
+ if (INODE_BUFFER_SIZE != write(dev_fd, inode_buffer, INODE_BUFFER_SIZE))
+ die("cannot write inodes");
}
static void get_dirsize(void)
@@ -613,12 +594,12 @@ static void get_dirsize(void)
char blk[BLOCK_SIZE];
int size;
-#ifdef CONFIG_FEATURE_MINIX2
+#if ENABLE_FEATURE_MINIX2
if (version2)
- block = Inode2[ROOT_INO].i_zone[0];
+ block = Inode2[MINIX_ROOT_INO].i_zone[0];
else
#endif
- block = Inode[ROOT_INO].i_zone[0];
+ 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) {
@@ -632,22 +613,20 @@ static void get_dirsize(void)
static void read_superblock(void)
{
- if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET))
- die("seek failed");
- if (BLOCK_SIZE != read(IN, super_block_buffer, BLOCK_SIZE))
- die("unable to read super block");
- if (MAGIC == MINIX_SUPER_MAGIC) {
- namelen = 14;
- dirsize = 16;
- version2 = 0;
- } else if (MAGIC == MINIX_SUPER_MAGIC2) {
+ xlseek(dev_fd, BLOCK_SIZE, SEEK_SET);
+ if (BLOCK_SIZE != full_read(dev_fd, superblock_buffer, BLOCK_SIZE))
+ die("cannot read superblock");
+ /* already initialized to:
+ namelen = 14;
+ dirsize = 16;
+ version2 = 0;
+ */
+ if (MAGIC == MINIX1_SUPER_MAGIC) {
+ } else if (MAGIC == MINIX1_SUPER_MAGIC2) {
namelen = 30;
dirsize = 32;
- version2 = 0;
-#ifdef CONFIG_FEATURE_MINIX2
+#if ENABLE_FEATURE_MINIX2
} else if (MAGIC == MINIX2_SUPER_MAGIC) {
- namelen = 14;
- dirsize = 16;
version2 = 1;
} else if (MAGIC == MINIX2_SUPER_MAGIC2) {
namelen = 30;
@@ -655,184 +634,149 @@ static void read_superblock(void)
version2 = 1;
#endif
} else
- die("bad magic number in super-block");
+ die("bad magic number in superblock");
if (ZONESIZE != 0 || BLOCK_SIZE != 1024)
- die("Only 1k blocks/zones supported");
+ die("only 1k blocks/zones supported");
if (IMAPS * BLOCK_SIZE * 8 < INODES + 1)
- die("bad s_imap_blocks field in super-block");
+ die("bad s_imap_blocks field in superblock");
if (ZMAPS * BLOCK_SIZE * 8 < ZONES - FIRSTZONE + 1)
- die("bad s_zmap_blocks field in super-block");
+ die("bad s_zmap_blocks field in superblock");
}
static void read_tables(void)
{
- inode_map = xmalloc(IMAPS * BLOCK_SIZE);
- zone_map = xmalloc(ZMAPS * BLOCK_SIZE);
- memset(inode_map, 0, sizeof(inode_map));
- memset(zone_map, 0, sizeof(zone_map));
+ 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("Unable to read inode map");
- if (ZMAPS * BLOCK_SIZE != read(IN, zone_map, ZMAPS * BLOCK_SIZE))
- die("Unable to read zone map");
- if (INODE_BUFFER_SIZE != read(IN, inode_buffer, INODE_BUFFER_SIZE))
- die("Unable to read inodes");
+ if (IMAPS * BLOCK_SIZE != read(dev_fd, inode_map, IMAPS * BLOCK_SIZE))
+ die("cannot read inode map");
+ if (ZMAPS * BLOCK_SIZE != read(dev_fd, zone_map, ZMAPS * BLOCK_SIZE))
+ die("cannot read zone map");
+ if (INODE_BUFFER_SIZE != read(dev_fd, inode_buffer, INODE_BUFFER_SIZE))
+ die("cannot read inodes");
if (NORM_FIRSTZONE != FIRSTZONE) {
- printf("Warning: Firstzone != Norm_firstzone\n");
+ printf("warning: firstzone!=norm_firstzone\n");
errors_uncorrected = 1;
}
get_dirsize();
- if (show) {
- printf("%ld inodes\n", INODES);
- printf("%ld blocks\n", ZONES);
- printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE);
- printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE);
- printf("Maxsize=%ld\n", MAXSIZE);
- printf("Filesystem state=%d\n", Super.s_state);
- printf("namelen=%d\n\n", namelen);
+ if (OPT_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 minix_inode *get_inode(unsigned int nr)
+static void get_inode_common(unsigned nr, uint16_t i_mode)
{
- struct minix_inode *inode;
-
- if (!nr || nr > INODES)
- return NULL;
total++;
- inode = Inode + nr;
if (!inode_count[nr]) {
if (!inode_in_use(nr)) {
- printf("Inode %d marked not used, but used for file '", nr);
- print_current_name();
- printf("'\n");
- if (repair) {
- if (ask("Mark in use", 1))
+ printf("Inode %d is marked as 'unused', but it is used "
+ "for file '%s'\n", nr, current_name);
+ if (OPT_repair) {
+ if (ask("Mark as 'in use'", 1))
mark_inode(nr);
- } else {
- errors_uncorrected = 1;
+ else
+ errors_uncorrected = 1;
}
}
- if (S_ISDIR(inode->i_mode))
+ if (S_ISDIR(i_mode))
directory++;
- else if (S_ISREG(inode->i_mode))
+ else if (S_ISREG(i_mode))
regular++;
- else if (S_ISCHR(inode->i_mode))
+ else if (S_ISCHR(i_mode))
chardev++;
- else if (S_ISBLK(inode->i_mode))
+ else if (S_ISBLK(i_mode))
blockdev++;
- else if (S_ISLNK(inode->i_mode))
+ else if (S_ISLNK(i_mode))
symlinks++;
- else if (S_ISSOCK(inode->i_mode));
- else if (S_ISFIFO(inode->i_mode));
+ else if (S_ISSOCK(i_mode));
+ else if (S_ISFIFO(i_mode));
else {
- print_current_name();
- printf(" has mode %05o\n", inode->i_mode);
+ printf("%s has mode %05o\n", current_name, i_mode);
}
-
} else
links++;
if (!++inode_count[nr]) {
- printf("Warning: inode count too big.\n");
+ printf("Warning: inode count too big\n");
inode_count[nr]--;
errors_uncorrected = 1;
}
+}
+
+static struct minix1_inode *get_inode(unsigned nr)
+{
+ struct minix1_inode *inode;
+
+ if (!nr || nr > INODES)
+ return NULL;
+ inode = Inode1 + nr;
+ get_inode_common(nr, inode->i_mode);
return inode;
}
-#ifdef CONFIG_FEATURE_MINIX2
-static struct minix2_inode *get_inode2(unsigned int nr)
+#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 marked not used, but used for file '", nr);
- print_current_name();
- printf("'\n");
- if (repair) {
- if (ask("Mark in use", 1))
- mark_inode(nr);
- else
- errors_uncorrected = 1;
- }
- }
- if (S_ISDIR(inode->i_mode))
- directory++;
- else if (S_ISREG(inode->i_mode))
- regular++;
- else if (S_ISCHR(inode->i_mode))
- chardev++;
- else if (S_ISBLK(inode->i_mode))
- blockdev++;
- else if (S_ISLNK(inode->i_mode))
- symlinks++;
- else if (S_ISSOCK(inode->i_mode));
- else if (S_ISFIFO(inode->i_mode));
- else {
- print_current_name();
- printf(" has mode %05o\n", inode->i_mode);
- }
- } else
- links++;
- if (!++inode_count[nr]) {
- printf("Warning: inode count too big.\n");
- inode_count[nr]--;
- errors_uncorrected = 1;
- }
+ get_inode_common(nr, inode->i_mode);
return inode;
}
#endif
static void check_root(void)
{
- struct minix_inode *inode = Inode + ROOT_INO;
+ struct minix1_inode *inode = Inode1 + MINIX_ROOT_INO;
if (!inode || !S_ISDIR(inode->i_mode))
die("root inode isn't a directory");
}
-#ifdef CONFIG_FEATURE_MINIX2
+#if ENABLE_FEATURE_MINIX2
static void check_root2(void)
{
- struct minix2_inode *inode = Inode2 + ROOT_INO;
+ 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(unsigned short *znr, int *corrected)
+static int add_zone_common(int block, smallint *corrected)
{
- int result;
- int block;
-
- result = 0;
- block = check_zone_nr(znr, corrected);
if (!block)
return 0;
if (zone_count[block]) {
- printf("Block has been used before. Now in file `");
- print_current_name();
- printf("'.");
+ printf("Already used block is reused in file '%s'. ",
+ current_name);
if (ask("Clear", 1)) {
- *znr = 0;
block = 0;
*corrected = 1;
+ return -1; /* "please zero out *znr" */
}
}
- if (!block)
- return 0;
if (!zone_in_use(block)) {
- printf("Block %d in file `", block);
- print_current_name();
- printf("' is marked not in use.");
+ printf("Block %d in file '%s' is marked as 'unused'. ",
+ block, current_name);
if (ask("Correct", 1))
mark_zone(block);
}
@@ -841,134 +785,127 @@ static int add_zone(unsigned short *znr, int *corrected)
return block;
}
-#ifdef CONFIG_FEATURE_MINIX2
-static int add_zone2(unsigned int *znr, int *corrected)
+static int add_zone(uint16_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("Block has been used before. Now in file `");
- print_current_name();
- printf("'.");
- if (ask("Clear", 1)) {
- *znr = 0;
- block = 0;
- *corrected = 1;
- }
+ block = check_zone_nr(znr, corrected);
+ block = add_zone_common(block, corrected);
+ if (block == -1) {
+ *znr = 0;
+ block = 0;
}
- if (!block)
- return 0;
- if (!zone_in_use(block)) {
- printf("Block %d in file `", block);
- print_current_name();
- printf("' is marked not in use.");
- if (ask("Correct", 1))
- mark_zone(block);
+ return block;
+}
+
+#if ENABLE_FEATURE_MINIX2
+static int add_zone2(uint32_t *znr, smallint *corrected)
+{
+ int block;
+
+ block = check_zone_nr2(znr, corrected);
+ block = add_zone_common(block, corrected);
+ if (block == -1) {
+ *znr = 0;
+ block = 0;
}
- if (!++zone_count[block])
- zone_count[block]--;
return block;
}
#endif
-static void add_zone_ind(unsigned short *znr, int *corrected)
+static void add_zone_ind(uint16_t *znr, smallint *corrected)
{
- static char blk[BLOCK_SIZE];
- int i, chg_blk = 0;
+ int i;
int block;
+ smallint chg_blk = 0;
block = add_zone(znr, corrected);
if (!block)
return;
- read_block(block, blk);
+ read_block(block, add_zone_ind_blk);
for (i = 0; i < (BLOCK_SIZE >> 1); i++)
- add_zone(i + (unsigned short *) blk, &chg_blk);
+ add_zone(i + (uint16_t *) add_zone_ind_blk, &chg_blk);
if (chg_blk)
- write_block(block, blk);
+ write_block(block, add_zone_ind_blk);
}
-#ifdef CONFIG_FEATURE_MINIX2
-static void add_zone_ind2(unsigned int *znr, int *corrected)
+#if ENABLE_FEATURE_MINIX2
+static void add_zone_ind2(uint32_t *znr, smallint *corrected)
{
- static char blk[BLOCK_SIZE];
- int i, chg_blk = 0;
+ int i;
int block;
+ smallint chg_blk = 0;
block = add_zone2(znr, corrected);
if (!block)
return;
- read_block(block, blk);
+ read_block(block, add_zone_ind_blk);
for (i = 0; i < BLOCK_SIZE >> 2; i++)
- add_zone2(i + (unsigned int *) blk, &chg_blk);
+ add_zone2(i + (uint32_t *) add_zone_ind_blk, &chg_blk);
if (chg_blk)
- write_block(block, blk);
+ write_block(block, add_zone_ind_blk);
}
#endif
-static void add_zone_dind(unsigned short *znr, int *corrected)
+static void add_zone_dind(uint16_t *znr, smallint *corrected)
{
- static char blk[BLOCK_SIZE];
- int i, blk_chg = 0;
+ int i;
int block;
+ smallint chg_blk = 0;
block = add_zone(znr, corrected);
if (!block)
return;
- read_block(block, blk);
+ read_block(block, add_zone_dind_blk);
for (i = 0; i < (BLOCK_SIZE >> 1); i++)
- add_zone_ind(i + (unsigned short *) blk, &blk_chg);
- if (blk_chg)
- write_block(block, blk);
+ add_zone_ind(i + (uint16_t *) add_zone_dind_blk, &chg_blk);
+ if (chg_blk)
+ write_block(block, add_zone_dind_blk);
}
-#ifdef CONFIG_FEATURE_MINIX2
-static void add_zone_dind2(unsigned int *znr, int *corrected)
+#if ENABLE_FEATURE_MINIX2
+static void add_zone_dind2(uint32_t *znr, smallint *corrected)
{
- static char blk[BLOCK_SIZE];
- int i, blk_chg = 0;
+ int i;
int block;
+ smallint chg_blk = 0;
block = add_zone2(znr, corrected);
if (!block)
return;
- read_block(block, blk);
+ read_block(block, add_zone_dind_blk);
for (i = 0; i < BLOCK_SIZE >> 2; i++)
- add_zone_ind2(i + (unsigned int *) blk, &blk_chg);
- if (blk_chg)
- write_block(block, blk);
+ add_zone_ind2(i + (uint32_t *) add_zone_dind_blk, &chg_blk);
+ if (chg_blk)
+ write_block(block, add_zone_dind_blk);
}
-static void add_zone_tind2(unsigned int *znr, int *corrected)
+static void add_zone_tind2(uint32_t *znr, smallint *corrected)
{
- static char blk[BLOCK_SIZE];
- int i, blk_chg = 0;
+ int i;
int block;
+ smallint chg_blk = 0;
block = add_zone2(znr, corrected);
if (!block)
return;
- read_block(block, blk);
+ read_block(block, add_zone_tind_blk);
for (i = 0; i < BLOCK_SIZE >> 2; i++)
- add_zone_dind2(i + (unsigned int *) blk, &blk_chg);
- if (blk_chg)
- write_block(block, blk);
+ add_zone_dind2(i + (uint32_t *) add_zone_tind_blk, &chg_blk);
+ if (chg_blk)
+ write_block(block, add_zone_tind_blk);
}
#endif
-static void check_zones(unsigned int i)
+static void check_zones(unsigned i)
{
- struct minix_inode *inode;
+ struct minix1_inode *inode;
if (!i || i > INODES)
return;
if (inode_count[i] > 1) /* have we counted this file already? */
return;
- inode = Inode + i;
+ 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++)
@@ -977,8 +914,8 @@ static void check_zones(unsigned int i)
add_zone_dind(8 + inode->i_zone, &changed);
}
-#ifdef CONFIG_FEATURE_MINIX2
-static void check_zones2(unsigned int i)
+#if ENABLE_FEATURE_MINIX2
+static void check_zones2(unsigned i)
{
struct minix2_inode *inode;
@@ -998,163 +935,133 @@ static void check_zones2(unsigned int i)
}
#endif
-static void check_file(struct minix_inode *dir, unsigned int offset)
+static void check_file(struct minix1_inode *dir, unsigned offset)
{
- static char blk[BLOCK_SIZE];
- struct minix_inode *inode;
+ 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 = *(unsigned short *) (name - 2);
+ read_block(block, check_file_blk);
+ name = check_file_blk + (offset % BLOCK_SIZE) + 2;
+ ino = *(uint16_t *) (name - 2);
if (ino > INODES) {
- print_current_name();
- printf(" contains a bad inode number for file '");
- printf("%.*s'.", namelen, name);
- if (ask(" Remove", 1)) {
- *(unsigned short *) (name - 2) = 0;
- write_block(block, blk);
+ 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, check_file_blk);
}
ino = 0;
}
- if (name_depth < MAX_DEPTH)
- strncpy(name_list[name_depth], name, namelen);
- name_depth++;
+ push_filename(name);
inode = get_inode(ino);
- name_depth--;
+ pop_filename();
if (!offset) {
- if (!inode || strcmp(".", name)) {
- print_current_name();
- printf(": bad directory: '.' isn't first\n");
- errors_uncorrected = 1;
- } else
+ 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)) {
- print_current_name();
- printf(": bad directory: '..' isn't second\n");
- errors_uncorrected = 1;
- } else
+ if (inode && strcmp("..", name) == 0)
return;
+ printf("%s: bad directory: '..' isn't second\n", current_name);
+ errors_uncorrected = 1;
}
if (!inode)
return;
- if (name_depth < MAX_DEPTH)
- strncpy(name_list[name_depth], name, namelen);
- name_depth++;
- if (list) {
- if (verbose)
+ push_filename(name);
+ if (OPT_list) {
+ if (OPT_verbose)
printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
- print_current_name();
- if (S_ISDIR(inode->i_mode))
- printf(":\n");
- else
- printf("\n");
+ printf("%s%s\n", current_name, S_ISDIR(inode->i_mode) ? ":" : "");
}
check_zones(ino);
if (inode && S_ISDIR(inode->i_mode))
recursive_check(ino);
- name_depth--;
- return;
+ pop_filename();
}
-#ifdef CONFIG_FEATURE_MINIX2
-static void check_file2(struct minix2_inode *dir, unsigned int offset)
+#if ENABLE_FEATURE_MINIX2
+static void check_file2(struct minix2_inode *dir, unsigned offset)
{
- static char blk[BLOCK_SIZE];
struct minix2_inode *inode;
int ino;
char *name;
int block;
block = map_block2(dir, offset / BLOCK_SIZE);
- read_block(block, blk);
- name = blk + (offset % BLOCK_SIZE) + 2;
- ino = *(unsigned short *) (name - 2);
+ read_block(block, check_file_blk);
+ name = check_file_blk + (offset % BLOCK_SIZE) + 2;
+ ino = *(uint16_t *) (name - 2);
if (ino > INODES) {
- print_current_name();
- printf(" contains a bad inode number for file '");
- printf("%.*s'.", namelen, name);
- if (ask(" Remove", 1)) {
- *(unsigned short *) (name - 2) = 0;
- write_block(block, blk);
+ 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, check_file_blk);
}
ino = 0;
}
- if (name_depth < MAX_DEPTH)
- strncpy(name_list[name_depth], name, namelen);
- name_depth++;
+ push_filename(name);
inode = get_inode2(ino);
- name_depth--;
+ pop_filename();
if (!offset) {
- if (!inode || strcmp(".", name)) {
- print_current_name();
- printf(": bad directory: '.' isn't first\n");
- errors_uncorrected = 1;
- } else
+ 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)) {
- print_current_name();
- printf(": bad directory: '..' isn't second\n");
- errors_uncorrected = 1;
- } else
+ if (inode && strcmp("..", name) == 0)
return;
+ printf("%s: bad directory: '..' isn't second\n", current_name);
+ errors_uncorrected = 1;
}
if (!inode)
return;
- name_depth++;
- if (list) {
- if (verbose)
+ push_filename(name);
+ if (OPT_list) {
+ if (OPT_verbose)
printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
- print_current_name();
- if (S_ISDIR(inode->i_mode))
- printf(":\n");
- else
- printf("\n");
+ printf("%s%s\n", current_name, S_ISDIR(inode->i_mode) ? ":" : "");
}
check_zones2(ino);
if (inode && S_ISDIR(inode->i_mode))
recursive_check2(ino);
- name_depth--;
- return;
+ pop_filename();
}
#endif
-static void recursive_check(unsigned int ino)
+static void recursive_check(unsigned ino)
{
- struct minix_inode *dir;
- unsigned int offset;
+ struct minix1_inode *dir;
+ unsigned offset;
- dir = Inode + ino;
+ dir = Inode1 + ino;
if (!S_ISDIR(dir->i_mode))
die("internal error");
if (dir->i_size < 2 * dirsize) {
- print_current_name();
- printf(": bad directory: size<32");
+ printf("%s: bad directory: size<32", current_name);
errors_uncorrected = 1;
}
for (offset = 0; offset < dir->i_size; offset += dirsize)
check_file(dir, offset);
}
-#ifdef CONFIG_FEATURE_MINIX2
-static void recursive_check2(unsigned int ino)
+#if ENABLE_FEATURE_MINIX2
+static void recursive_check2(unsigned ino)
{
struct minix2_inode *dir;
- unsigned int offset;
+ unsigned offset;
dir = Inode2 + ino;
if (!S_ISDIR(dir->i_mode))
die("internal error");
if (dir->i_size < 2 * dirsize) {
- print_current_name();
- printf(": bad directory: size < 32");
+ printf("%s: bad directory: size<32", current_name);
errors_uncorrected = 1;
}
for (offset = 0; offset < dir->i_size; offset += dirsize)
@@ -1164,11 +1071,10 @@ static void recursive_check2(unsigned int ino)
static int bad_zone(int i)
{
- char buffer[1024];
+ 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));
+ xlseek(dev_fd, BLOCK_SIZE * i, SEEK_SET);
+ return (BLOCK_SIZE != full_read(dev_fd, buffer, BLOCK_SIZE));
}
static void check_counts(void)
@@ -1176,42 +1082,43 @@ static void check_counts(void)
int i;
for (i = 1; i <= INODES; i++) {
- if (!inode_in_use(i) && Inode[i].i_mode && warn_mode) {
- printf("Inode %d mode not cleared.", i);
+ if (OPT_warn_mode && Inode1[i].i_mode && !inode_in_use(i)) {
+ printf("Inode %d has non-zero mode. ", i);
if (ask("Clear", 1)) {
- Inode[i].i_mode = 0;
+ Inode1[i].i_mode = 0;
changed = 1;
}
}
if (!inode_count[i]) {
if (!inode_in_use(i))
continue;
- printf("Inode %d not used, marked used in the bitmap.", i);
+ 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 used, marked unused in the bitmap.", i);
+ printf("Inode %d is used, but marked as 'unused' in the bitmap. ", i);
if (ask("Set", 1))
mark_inode(i);
}
- if (Inode[i].i_nlinks != inode_count[i]) {
- printf("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.",
- i, Inode[i].i_mode, Inode[i].i_nlinks, inode_count[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)) {
- Inode[i].i_nlinks = inode_count[i];
+ Inode1[i].i_nlinks = inode_count[i];
changed = 1;
}
}
}
for (i = FIRSTZONE; i < ZONES; i++) {
- if (zone_in_use(i) == zone_count[i])
+ if ((zone_in_use(i) != 0) == zone_count[i])
continue;
if (!zone_count[i]) {
if (bad_zone(i))
continue;
- printf("Zone %d: marked in use, no file uses it.", i);
+ printf("Zone %d is marked 'in use', but no file uses it. ", i);
if (ask("Unmark", 1))
unmark_zone(i);
continue;
@@ -1221,14 +1128,14 @@ static void check_counts(void)
}
}
-#ifdef CONFIG_FEATURE_MINIX2
+#if ENABLE_FEATURE_MINIX2
static void check_counts2(void)
{
int i;
for (i = 1; i <= INODES; i++) {
- if (!inode_in_use(i) && Inode2[i].i_mode && warn_mode) {
- printf("Inode %d mode not cleared.", i);
+ if (OPT_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;
@@ -1237,20 +1144,20 @@ static void check_counts2(void)
if (!inode_count[i]) {
if (!inode_in_use(i))
continue;
- printf("Inode %d not used, marked used in the bitmap.", i);
+ 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 used, marked unused in the bitmap.", 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]);
+ 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;
@@ -1258,12 +1165,12 @@ static void check_counts2(void)
}
}
for (i = FIRSTZONE; i < ZONES; i++) {
- if (zone_in_use(i) == zone_count[i])
+ if ((zone_in_use(i) != 0) == zone_count[i])
continue;
if (!zone_count[i]) {
if (bad_zone(i))
continue;
- printf("Zone %d: marked in use, no file uses it.", i);
+ printf("Zone %d is marked 'in use', but no file uses it. ", i);
if (ask("Unmark", 1))
unmark_zone(i);
continue;
@@ -1278,195 +1185,121 @@ static void check(void)
{
memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
memset(zone_count, 0, ZONES * sizeof(*zone_count));
- check_zones(ROOT_INO);
- recursive_check(ROOT_INO);
+ check_zones(MINIX_ROOT_INO);
+ recursive_check(MINIX_ROOT_INO);
check_counts();
}
-#ifdef CONFIG_FEATURE_MINIX2
+#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(ROOT_INO);
- recursive_check2(ROOT_INO);
+ check_zones2(MINIX_ROOT_INO);
+ recursive_check2(MINIX_ROOT_INO);
check_counts2();
}
+#else
+void check2(void);
#endif
-/* Wed Feb 9 15:17:06 MST 2000 */
-/* dynamically allocate name_list (instead of making it static) */
-static void alloc_name_list(void)
-{
- int i;
-
- name_list = xmalloc(sizeof(char *) * MAX_DEPTH);
- for (i = 0; i < MAX_DEPTH; i++)
- name_list[i] = xmalloc(sizeof(char) * BUFSIZ + 1);
-}
-
-#ifdef CONFIG_FEATURE_CLEAN_UP
-/* execute this atexit() to deallocate name_list[] */
-/* piptigger was here */
-static void free_name_list(void)
-{
- int i;
-
- if (name_list) {
- for (i = 0; i < MAX_DEPTH; i++) {
- free(name_list[i]);
- }
- free(name_list);
- }
-}
-#endif
-
-extern int fsck_minix_main(int argc, char **argv)
+int fsck_minix_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int fsck_minix_main(int argc UNUSED_PARAM, char **argv)
{
struct termios tmp;
- int count;
int retcode = 0;
- alloc_name_list();
-#ifdef CONFIG_FEATURE_CLEAN_UP
- /* Don't bother to free memory. Exit does
- * that automagically, so we can save a few bytes */
- atexit(free_name_list);
-#endif
+ xfunc_error_retval = 8;
- if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE)
- die("bad inode size");
-#ifdef CONFIG_FEATURE_MINIX2
- if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
- die("bad v2 inode size");
-#endif
- while (argc-- > 1) {
- argv++;
- if (argv[0][0] != '-') {
- if (device_name)
- bb_show_usage();
- else
- 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) {
+ INIT_G();
+
+ opt_complementary = "=1:ar"; /* one argument; -a assumes -r */
+ getopt32(argv, OPTION_STR);
+ argv += optind;
+ device_name = argv[0];
+
+ check_mount(); /* trying to check a mounted filesystem? */
+ if (OPT_manual) {
if (!isatty(0) || !isatty(1))
die("need terminal for interactive repairs");
}
- IN = open(device_name, repair ? O_RDWR : O_RDONLY);
- if (IN < 0){
- fprintf(stderr,"unable to open device '%s'.\n",device_name);
- leave(8);
- }
- for (count = 0; count < 3; count++)
- sync();
+ xmove_fd(xopen(device_name, OPT_repair ? O_RDWR : O_RDONLY), dev_fd);
+
+ /*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
+ * flags and whether or not the -f switch was specified on the
* command line.
*/
- printf("%s, %s\n", bb_applet_name, program_version);
- if (!(Super.s_state & MINIX_ERROR_FS) &&
- (Super.s_state & MINIX_VALID_FS) && !force) {
- if (repair)
- printf("%s is clean, no check.\n", device_name);
- return retcode;
- } else if (force)
- printf("Forcing filesystem check on %s.\n", device_name);
- else if (repair)
- printf("Filesystem on %s is dirty, needs checking.\n",
+ printf("%s: %s\n", applet_name, bb_banner);
+
+ if (!(Super.s_state & MINIX_ERROR_FS)
+ && (Super.s_state & MINIX_VALID_FS) && !OPT_force
+ ) {
+ if (OPT_repair)
+ printf("%s is clean, check is skipped\n", device_name);
+ return 0;
+ } else if (OPT_force)
+ printf("Forcing filesystem check on %s\n", device_name);
+ else if (OPT_repair)
+ printf("Filesystem on %s is dirty, needs checking\n",
device_name);
read_tables();
- if (repair && !automatic) {
- tcgetattr(0, &termios);
- tmp = termios;
+ if (OPT_manual) {
+ tcgetattr(0, &sv_termios);
+ tmp = sv_termios;
tmp.c_lflag &= ~(ICANON | ECHO);
- tcsetattr(0, TCSANOW, &tmp);
+ tcsetattr_stdin_TCSANOW(&tmp);
termios_set = 1;
}
-#ifdef CONFIG_FEATURE_MINIX2
+
if (version2) {
check_root2();
check2();
- } else
-#endif
- {
+ } else {
check_root();
check();
}
- if (verbose) {
+
+ if (OPT_verbose) {
int i, free_cnt;
for (i = 1, free_cnt = 0; i <= INODES; i++)
if (!inode_in_use(i))
free_cnt++;
- printf("\n%6ld inodes used (%ld%%)\n", (INODES - 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("%6ld zones used (%ld%%)\n", (ZONES - free_cnt),
- 100 * (ZONES - free_cnt) / ZONES);
- printf("\n%6d regular files\n"
- "%6d directories\n"
- "%6d character device files\n"
- "%6d block device files\n"
- "%6d links\n"
- "%6d symbolic links\n"
+ 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"
- "%6d files\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("----------------------------\n"
- "FILE SYSTEM HAS BEEN CHANGED\n"
- "----------------------------\n");
- for (count = 0; count < 3; count++)
- sync();
- } else if (repair)
- write_super_block();
-
- if (repair && !automatic)
- tcsetattr(0, TCSANOW, &termios);
+ printf("FILE SYSTEM HAS BEEN CHANGED\n");
+ sync();
+ } else if (OPT_repair)
+ write_superblock();
+
+ if (OPT_manual)
+ tcsetattr_stdin_TCSANOW(&sv_termios);
if (changed)
retcode += 3;
diff --git a/release/src/router/busybox/util-linux/getopt.c b/release/src/router/busybox/util-linux/getopt.c
index 25eeab69..fd672873 100644
--- a/release/src/router/busybox/util-linux/getopt.c
+++ b/release/src/router/busybox/util-linux/getopt.c
@@ -1,20 +1,9 @@
+/* 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>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/*
@@ -33,49 +22,51 @@
* 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
+ * Added NLS support (partly written by Arkadiusz Mickiewicz
* <misiek@misiek.eu.org>)
* Ported to Busybox - Alfred M. Szmidt <ams@trillian.itslinux.org>
* Removed --version/-V and --help/-h in
- * Removed prase_error(), using bb_error_msg() from Busybox instead
+ * Removed parse_error(), using bb_error_msg() from Busybox instead
* Replaced our_malloc with xmalloc and our_realloc with xrealloc
*
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <ctype.h>
#include <getopt.h>
-
-#include "busybox.h"
+#include "libbb.h"
/* NON_OPT is the code that is returned when a non-option is found in '+'
mode */
-static const int NON_OPT = 1;
+enum {
+ NON_OPT = 1,
+#if ENABLE_GETOPT_LONG
/* LONG_OPT is the code that is returned when a long option is found. */
-static const int LONG_OPT = 2;
-
-/* The shells recognized. */
-typedef enum {BASH,TCSH} shell_t;
-
+ LONG_OPT = 2
+#endif
+};
-/* 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; /* 0 is not quiet. */
-static int quiet_output=0; /* 0 is not quiet. */
-static int quote=1; /* 1 is do quote. */
-static int alternative=0; /* 0 is getopt_long, 1 is getopt_long_only */
+/* For finding activated option flags. Must match getopt32 call! */
+enum {
+ OPT_o = 0x1, // -o
+ OPT_n = 0x2, // -n
+ OPT_q = 0x4, // -q
+ OPT_Q = 0x8, // -Q
+ OPT_s = 0x10, // -s
+ OPT_T = 0x20, // -T
+ OPT_u = 0x40, // -u
+#if ENABLE_GETOPT_LONG
+ OPT_a = 0x80, // -a
+ OPT_l = 0x100, // -l
+#endif
+ SHELL_IS_TCSH = 0x8000, /* hijack this bit for other purposes */
+};
-/* 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);
+/* 0 is getopt_long, 1 is getopt_long_only */
+#define alternative (option_mask32 & OPT_a)
+#define quiet_errors (option_mask32 & OPT_q)
+#define quiet_output (option_mask32 & OPT_Q)
+#define quote (!(option_mask32 & OPT_u))
+#define shell_TCSH (option_mask32 & SHELL_IS_TCSH)
/*
* This function 'normalizes' a single argument: it puts single quotes around
@@ -86,59 +77,61 @@ static void set_shell(const char *new_shell);
* This function returns a pointer to a buffer that is overwritten by
* each call.
*/
-const char *normalize(const char *arg)
+static const char *normalize(const char *arg)
{
- static char *BUFFER=NULL;
- const char *argptr=arg;
- char *bufptr;
-
- free(BUFFER);
-
- if (!quote) { /* Just copy arg */
- BUFFER=bb_xstrdup(arg);
- return BUFFER;
- }
-
- /* Each character in arg may take upto 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;
+ char *bufptr;
+#if ENABLE_FEATURE_CLEAN_UP
+ static char *BUFFER = NULL;
+ free(BUFFER);
+#else
+ char *BUFFER;
+#endif
+
+ 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 (*arg) {
+ if (*arg == '\'') {
+ /* Quote: replace it with: '\'' */
+ *bufptr ++= '\'';
+ *bufptr ++= '\\';
+ *bufptr ++= '\'';
+ *bufptr ++= '\'';
+ } else if (shell_TCSH && *arg == '!') {
+ /* Exclamation mark: replace it with: \! */
+ *bufptr ++= '\'';
+ *bufptr ++= '\\';
+ *bufptr ++= '!';
+ *bufptr ++= '\'';
+ } else if (shell_TCSH && *arg == '\n') {
+ /* Newline: replace it with: \n */
+ *bufptr ++= '\\';
+ *bufptr ++= 'n';
+ } else if (shell_TCSH && isspace(*arg)) {
+ /* Non-newline whitespace: replace it with \<ws> */
+ *bufptr ++= '\'';
+ *bufptr ++= '\\';
+ *bufptr ++= *arg;
+ *bufptr ++= '\'';
+ } else
+ /* Just copy */
+ *bufptr ++= *arg;
+ arg++;
+ }
+ *bufptr ++= '\'';
+ *bufptr ++= '\0';
+ return BUFFER;
}
/*
@@ -148,244 +141,214 @@ const char *normalize(const char *arg)
* 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)
+#if !ENABLE_GETOPT_LONG
+#define generate_output(argv,argc,optstr,longopts) \
+ generate_output(argv,argc,optstr)
+#endif
+static 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++]));
- printf("\n");
- }
- return exit_code;
+ int exit_code = 0; /* We assume everything will be OK */
+ int opt;
+#if ENABLE_GETOPT_LONG
+ int longindex;
+#endif
+ const char *charptr;
+
+ if (quiet_errors) /* No error reporting from getopt(3) */
+ opterr = 0;
+
+ /* We used it already in main() in getopt32(),
+ * we *must* reset getopt(3): */
+#ifdef __GLIBC__
+ optind = 0;
+#else /* BSD style */
+ optind = 1;
+ /* optreset = 1; */
+#endif
+
+ while (1) {
+ opt =
+#if ENABLE_GETOPT_LONG
+ alternative ?
+ getopt_long_only(argc, argv, optstr, longopts, &longindex) :
+ getopt_long(argc, argv, optstr, longopts, &longindex);
+#else
+ getopt(argc, argv, optstr);
+#endif
+ if (opt == -1)
+ break;
+ if (opt == '?' || opt == ':' )
+ exit_code = 1;
+ else if (!quiet_output) {
+#if ENABLE_GETOPT_LONG
+ if (opt == LONG_OPT) {
+ printf(" --%s", longopts[longindex].name);
+ if (longopts[longindex].has_arg)
+ printf(" %s",
+ normalize(optarg ? optarg : ""));
+ } else
+#endif
+ 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++]));
+ bb_putchar('\n');
+ }
+ return exit_code;
}
-static struct option *long_options=NULL;
-static int long_options_length=0; /* Length of array */
-static int long_options_nr=0; /* Nr of used elements in array */
-static const int 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=bb_xstrdup(name);
- }
- long_options_nr++;
-}
-
-
+#if ENABLE_GETOPT_LONG
/*
* 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)
+static struct option *add_long_options(struct option *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");
- }
+ int long_nr = 0;
+ int arg_opt, tlen;
+ char *tokptr = strtok(options, ", \t\n");
+
+ if (long_options)
+ while (long_options[long_nr].name)
+ long_nr++;
+
+ while (tokptr) {
+ arg_opt = no_argument;
+ tlen = strlen(tokptr);
+ if (tlen) {
+ tlen--;
+ if (tokptr[tlen] == ':') {
+ arg_opt = required_argument;
+ if (tlen && tokptr[tlen-1] == ':') {
+ tlen--;
+ arg_opt = optional_argument;
+ }
+ tokptr[tlen] = '\0';
+ if (tlen == 0)
+ bb_error_msg_and_die("empty long option specified");
+ }
+ long_options = xrealloc_vector(long_options, 4, long_nr);
+ long_options[long_nr].has_arg = arg_opt;
+ /*long_options[long_nr].flag = NULL; - xrealloc_vector did it */
+ long_options[long_nr].val = LONG_OPT;
+ long_options[long_nr].name = xstrdup(tokptr);
+ long_nr++;
+ /*memset(&long_options[long_nr], 0, sizeof(long_options[0])); - xrealloc_vector did it */
+ }
+ tokptr = strtok(NULL, ", \t\n");
+ }
+ return long_options;
}
+#endif
-void set_shell(const char *new_shell)
+static 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");
+ if (!strcmp(new_shell, "bash") || !strcmp(new_shell, "sh"))
+ return;
+ if (!strcmp(new_shell, "tcsh") || !strcmp(new_shell, "csh"))
+ option_mask32 |= SHELL_IS_TCSH;
+ else
+ bb_error_msg("unknown shell '%s', assuming bash", new_shell);
}
/* Exit codes:
- * 0) No errors, succesful operation.
+ * 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 struct option longopts[]=
+#if ENABLE_GETOPT_LONG
+static const char getopt_longopts[] ALIGN1 =
+ "options\0" Required_argument "o"
+ "longoptions\0" Required_argument "l"
+ "quiet\0" No_argument "q"
+ "quiet-output\0" No_argument "Q"
+ "shell\0" Required_argument "s"
+ "test\0" No_argument "T"
+ "unquoted\0" No_argument "u"
+ "alternative\0" No_argument "a"
+ "name\0" Required_argument "n"
+ ;
+#endif
+
+int getopt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int getopt_main(int argc, char **argv)
{
- {"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[])
-{
- 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) {
- quote=0;
- optstr=xmalloc(strlen(argv[1])+1);
- strcpy(optstr,argv[1]+strspn(argv[1],"-+"));
- argv[1]=argv[0];
- return (generate_output(argv+1,argc-1,optstr,long_options));
- }
-
- while ((opt=getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF)
- switch (opt) {
- case 'a':
- alternative=1;
- break;
- case 'o':
- free(optstr);
- optstr=bb_xstrdup(optarg);
- break;
- case 'l':
- add_long_options(optarg);
- break;
- case 'n':
- free(name);
- name=bb_xstrdup(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=bb_xstrdup(argv[optind]);
- 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));
+ char *optstr = NULL;
+ char *name = NULL;
+ unsigned opt;
+ const char *compatible;
+ char *s_arg;
+#if ENABLE_GETOPT_LONG
+ struct option *long_options = NULL;
+ llist_t *l_arg = NULL;
+#endif
+
+ compatible = getenv("GETOPT_COMPATIBLE"); /* used as yes/no flag */
+
+ if (argc == 1) {
+ if (compatible) {
+ /* For some reason, the original getopt gave no error
+ when there were no arguments. */
+ printf(" --\n");
+ return 0;
+ }
+ bb_error_msg_and_die("missing optstring argument");
+ }
+
+ if (argv[1][0] != '-' || compatible) {
+ char *s;
+
+ option_mask32 |= OPT_u; /* quoting off */
+ s = xstrdup(argv[1] + strspn(argv[1], "-+"));
+ argv[1] = argv[0];
+ return generate_output(argv+1, argc-1, s, long_options);
+ }
+
+#if !ENABLE_GETOPT_LONG
+ opt = getopt32(argv, "+o:n:qQs:Tu", &optstr, &name, &s_arg);
+#else
+ applet_long_options = getopt_longopts;
+ opt_complementary = "l::";
+ opt = getopt32(argv, "+o:n:qQs:Tual:",
+ &optstr, &name, &s_arg, &l_arg);
+ /* Effectuate the read options for the applet itself */
+ while (l_arg) {
+ long_options = add_long_options(long_options, llist_pop(&l_arg));
+ }
+#endif
+
+ if (opt & OPT_s) {
+ set_shell(s_arg);
+ }
+
+ if (opt & OPT_T) {
+ return 4;
+ }
+
+ /* All options controlling the applet have now been parsed */
+ if (!optstr) {
+ if (optind >= argc)
+ bb_error_msg_and_die("missing optstring argument");
+ optstr = argv[optind++];
+ }
+
+ argv[optind-1] = name ? name : argv[0];
+ return generate_output(argv+optind-1, argc-optind+1, optstr, long_options);
}
-
-/*
- Local Variables:
- c-file-style: "linux"
- c-basic-offset: 4
- tab-width: 4
- End:
-*/
diff --git a/release/src/router/busybox/util-linux/hexdump.c b/release/src/router/busybox/util-linux/hexdump.c
index 1858b08d..48edd70a 100644
--- a/release/src/router/busybox/util-linux/hexdump.c
+++ b/release/src/router/busybox/util-linux/hexdump.c
@@ -1,3 +1,4 @@
+/* vi: set sw=4 ts=4: */
/*
* hexdump implementation for busybox
* Based on code from util-linux v 2.11l
@@ -5,138 +6,146 @@
* Copyright (c) 1989
* The Regents of the University of California. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Original copyright notice is retained at the end of this file.
+ * Licensed under GPLv2 or later, see file License in this tarball for details.
*/
-#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-#include "busybox.h"
+#include "libbb.h"
#include "dump.h"
-static void bb_dump_addfile(char *name)
+/* This is a NOEXEC applet. Be very careful! */
+
+static void bb_dump_addfile(dumper_t *dumper, char *name)
{
- register char *p;
+ char *p;
FILE *fp;
char *buf;
- fp = bb_xfopen(name, "r");
-
- while ((buf = bb_get_chomped_line_from_file(fp)) != NULL) {
- p = (char *) bb_skip_whitespace(buf);
-
+ fp = xfopen_for_read(name);
+ while ((buf = xmalloc_fgetline(fp)) != NULL) {
+ p = skip_whitespace(buf);
if (*p && (*p != '#')) {
- bb_dump_add(p);
+ bb_dump_add(dumper, 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 *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 add_first[] ALIGN1 = "\"%07.7_Ax\n\"";
-static const char hexdump_opts[] = "bcdoxe:f:n:s:v";
+static const char hexdump_opts[] ALIGN1 = "bcdoxCe:f:n:s:v" USE_FEATURE_HEXDUMP_REVERSE("R");
static const struct suffix_mult suffixes[] = {
- {"b", 512 },
- {"k", 1024 },
- {"m", 1024*1024 },
- {NULL, 0 }
+ { "b", 512 },
+ { "k", 1024 },
+ { "m", 1024*1024 },
+ { }
};
+int hexdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int hexdump_main(int argc, char **argv)
{
-// register FS *tfs;
+ dumper_t *dumper = alloc_dumper();
const char *p;
int ch;
+#if ENABLE_FEATURE_HEXDUMP_REVERSE
+ FILE *fp;
+ smallint rdump = 0;
+#endif
- bb_dump_vflag = FIRST;
- bb_dump_length = -1;
+ if (ENABLE_HD && !applet_name[2]) { /* we are "hd" */
+ ch = 'C';
+ goto hd_applet;
+ }
+ /* We cannot use getopt32: in hexdump options are cumulative.
+ * E.g. "hexdump -C -C file" should dump each line twice */
while ((ch = getopt(argc, argv, hexdump_opts)) > 0) {
- if ((p = strchr(hexdump_opts, ch)) != NULL) {
- if ((p - hexdump_opts) < 5) {
- bb_dump_add(add_first);
- bb_dump_add(add_strings[(int)(p - hexdump_opts)]);
- } else {
- /* Sae 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 = bb_xgetularg10_bnd(optarg, 0, INT_MAX);
- } /* else */
- if (ch == 's') {
- bb_dump_skip = bb_xgetularg_bnd_sfx(optarg, 10, 0, LONG_MAX, suffixes);
- } /* else */
- if (ch == 'v') {
- bb_dump_vflag = ALL;
- }
- }
- } else {
+ p = strchr(hexdump_opts, ch);
+ if (!p)
bb_show_usage();
+ if ((p - hexdump_opts) < 5) {
+ bb_dump_add(dumper, add_first);
+ bb_dump_add(dumper, add_strings[(int)(p - hexdump_opts)]);
+ }
+ /* Save a little bit of space below by omitting the 'else's. */
+ if (ch == 'C') {
+ hd_applet:
+ bb_dump_add(dumper, "\"%08.8_Ax\n\"");
+ bb_dump_add(dumper, "\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" ");
+ bb_dump_add(dumper, "\" |\" 16/1 \"%_p\" \"|\\n\"");
+ }
+ if (ch == 'e') {
+ bb_dump_add(dumper, optarg);
+ } /* else */
+ if (ch == 'f') {
+ bb_dump_addfile(dumper, optarg);
+ } /* else */
+ if (ch == 'n') {
+ dumper->dump_length = xatoi_u(optarg);
+ } /* else */
+ if (ch == 's') {
+ dumper->dump_skip = xatoul_range_sfx(optarg, 0, LONG_MAX, suffixes);
+ } /* else */
+ if (ch == 'v') {
+ dumper->dump_vflag = ALL;
+ }
+#if ENABLE_FEATURE_HEXDUMP_REVERSE
+ if (ch == 'R') {
+ rdump = 1;
}
+#endif
}
- if (!bb_dump_fshead) {
- bb_dump_add(add_first);
- bb_dump_add("\"%07.7_ax \" 8/2 \"%04x \" \"\\n\"");
+ if (!dumper->fshead) {
+ bb_dump_add(dumper, add_first);
+ bb_dump_add(dumper, "\"%07.7_ax \" 8/2 \"%04x \" \"\\n\"");
}
argv += optind;
- return(bb_dump_dump(argv));
+#if !ENABLE_FEATURE_HEXDUMP_REVERSE
+ return bb_dump_dump(dumper, argv);
+#else
+ if (!rdump) {
+ return bb_dump_dump(dumper, argv);
+ }
+
+ /* -R: reverse of 'hexdump -Cv' */
+ fp = stdin;
+ if (!*argv) {
+ argv--;
+ goto jump_in;
+ }
+
+ do {
+ char *buf;
+ fp = xfopen_for_read(*argv);
+ jump_in:
+ while ((buf = xmalloc_fgetline(fp)) != NULL) {
+ p = buf;
+ while (1) {
+ /* skip address or previous byte */
+ while (isxdigit(*p)) p++;
+ while (*p == ' ') p++;
+ /* '|' char will break the line */
+ if (!isxdigit(*p) || sscanf(p, "%x ", &ch) != 1)
+ break;
+ putchar(ch);
+ }
+ free(buf);
+ }
+ fclose(fp);
+ } while (*++argv);
+
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+#endif
}
-/*
- * Copyright (c) 1989 The 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. 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.
- */
diff --git a/release/src/router/busybox/util-linux/hwclock.c b/release/src/router/busybox/util-linux/hwclock.c
index 105246aa..3d28364e 100644
--- a/release/src/router/busybox/util-linux/hwclock.c
+++ b/release/src/router/busybox/util-linux/hwclock.c
@@ -4,259 +4,124 @@
*
* Copyright (C) 2002 Robert Griebl <griebl@gmx.de>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-
#include <sys/utsname.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <syslog.h>
-#include <string.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <sys/time.h>
-#include <time.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-
-/* Copied from linux/rtc.h to eliminate the kernel dependancy */
-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 */
-
+#include "libbb.h"
+#include "rtc_.h"
-#ifdef CONFIG_FEATURE_HWCLOCK_LONGOPTIONS
+#if ENABLE_FEATURE_HWCLOCK_LONG_OPTIONS
# ifndef _GNU_SOURCE
# define _GNU_SOURCE
# endif
#endif
-#include <getopt.h>
+static const char *rtcname;
-
-enum OpMode {
- SHOW,
- SYSTOHC,
- HCTOSYS
-};
-
-
-time_t read_rtc ( int utc )
+static time_t read_rtc(int utc)
{
- int rtc;
- struct tm tm;
- char *oldtz = 0;
- time_t t = 0;
+ time_t ret;
+ int fd;
- if (( rtc = open ( "/dev/rtc", O_RDONLY )) < 0 ) {
- if (( rtc = open ( "/dev/misc/rtc", O_RDONLY )) < 0 )
- bb_perror_msg_and_die ( "Could not access RTC" );
- }
- memset ( &tm, 0, sizeof( struct tm ));
- if ( ioctl ( rtc, RTC_RD_TIME, &tm ) < 0 )
- bb_perror_msg_and_die ( "Could not read time from RTC" );
- tm. tm_isdst = -1; // not known
-
- close ( rtc );
+ fd = rtc_xopen(&rtcname, O_RDONLY);
+ ret = rtc_read_time(fd, utc);
+ close(fd);
- 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;
+ return ret;
}
-void write_rtc ( time_t t, int utc )
+static void write_rtc(time_t t, int utc)
{
- int rtc;
struct tm tm;
+ int rtc = rtc_xopen(&rtcname, O_WRONLY);
- if (( rtc = open ( "/dev/rtc", O_WRONLY )) < 0 ) {
- if (( rtc = open ( "/dev/misc/rtc", O_WRONLY )) < 0 )
- bb_perror_msg_and_die ( "Could not access RTC" );
- }
-
-// printf ( "1\n" );
-
- tm = *( utc ? gmtime ( &t ) : localtime ( &t ));
- tm. tm_isdst = 0;
-
-// printf ( "2\n") ;
-
- if ( ioctl ( rtc, RTC_SET_TIME, &tm ) < 0 )
- bb_perror_msg_and_die ( "Could not set the RTC time" );
-
- close ( rtc );
+ tm = *(utc ? gmtime(&t) : localtime(&t));
+ tm.tm_isdst = 0;
+
+ xioctl(rtc, RTC_SET_TIME, &tm);
+
+ close(rtc);
}
-int show_clock ( int utc )
+static void show_clock(int utc)
{
- struct tm *ptm;
+ //struct tm *ptm;
time_t t;
- char buffer [64];
+ char *cp;
- t = read_rtc ( utc );
- ptm = localtime ( &t ); /* Sets 'tzname[]' */
-
- safe_strncpy ( buffer, ctime ( &t ), sizeof( buffer ));
- if ( buffer [0] )
- buffer [bb_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 );
-
- return 0;
+ t = read_rtc(utc);
+ //ptm = localtime(&t); /* Sets 'tzname[]' */
+
+ cp = ctime(&t);
+ if (cp[0])
+ cp[strlen(cp) - 1] = '\0';
+
+ //printf("%s %.6f seconds %s\n", cp, 0.0, utc ? "" : (ptm->tm_isdst ? tzname[1] : tzname[0]));
+ printf("%s 0.000000 seconds\n", cp);
}
-int to_sys_clock ( int utc )
+static void to_sys_clock(int utc)
{
- struct timeval tv = { 0, 0 };
+ struct timeval tv;
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;
+ tv.tv_sec = read_rtc(utc);
+ tv.tv_usec = 0;
+ if (settimeofday(&tv, &tz))
+ bb_perror_msg_and_die("settimeofday() failed");
}
-int from_sys_clock ( int utc )
+static void from_sys_clock(int utc)
{
- struct timeval tv = { 0, 0 };
- struct timezone tz = { 0, 0 };
+ struct timeval tv;
- if ( gettimeofday ( &tv, &tz ))
- bb_perror_msg_and_die ( "gettimeofday() failed" );
-
- write_rtc ( tv. tv_sec, utc );
- return 0;
+ gettimeofday(&tv, NULL);
+ //if (gettimeofday(&tv, NULL))
+ // bb_perror_msg_and_die("gettimeofday() failed");
+ write_rtc(tv.tv_sec, 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 check_utc ( void )
+int hwclock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int hwclock_main(int argc UNUSED_PARAM, char **argv)
{
- int utc = 0;
- FILE *f = fopen ( "/etc/adjtime", "r" );
-
- if ( f ) {
- char buffer [128];
-
- while ( fgets ( buffer, sizeof( buffer ), f )) {
- int len = bb_strlen ( buffer );
-
- while ( len && isspace ( buffer [len - 1] ))
- len--;
-
- buffer [len] = 0;
-
- if ( strncmp ( buffer, "UTC", 3 ) == 0 ) {
- utc = 1;
- break;
- }
- }
- fclose ( f );
- }
- return utc;
-}
-
-extern int hwclock_main ( int argc, char **argv )
-{
- int opt;
- enum OpMode mode = SHOW;
- int utc = 0;
- int utc_arg = 0;
-
-#ifdef CONFIG_FEATURE_HWCLOCK_LONGOPTIONS
- struct option long_options[] = {
- { "show", 0, 0, 'r' },
- { "utc", 0, 0, 'u' },
- { "localtime", 0, 0, 'l' },
- { "hctosys", 0, 0, 's' },
- { "systohc", 0, 0, 'w' },
- { 0, 0, 0, 0 }
- };
-
- while (( opt = getopt_long ( argc, argv, "rwsul", long_options, 0 )) != EOF ) {
-#else
- while (( opt = getopt ( argc, argv, "rwsul" )) != EOF ) {
+ unsigned opt;
+ int utc;
+
+#if ENABLE_FEATURE_HWCLOCK_LONG_OPTIONS
+ static const char hwclock_longopts[] ALIGN1 =
+ "localtime\0" No_argument "l"
+ "utc\0" No_argument "u"
+ "show\0" No_argument "r"
+ "hctosys\0" No_argument "s"
+ "systohc\0" No_argument "w"
+ "file\0" Required_argument "f"
+ ;
+ applet_long_options = hwclock_longopts;
#endif
- switch ( opt ) {
- case 'r':
- mode = SHOW;
- break;
- case 'w':
- mode = SYSTOHC;
- break;
- case 's':
- mode = HCTOSYS;
- break;
- case 'u':
- utc = 1;
- utc_arg = 1;
- break;
- case 'l': // -l is not supported by the normal hwclock (only --localtime)
- utc = 0;
- utc_arg = 1;
- break;
- default:
- bb_show_usage();
- break;
- }
- }
-
- if ( !utc_arg )
- utc = check_utc ( );
-
- switch ( mode ) {
- case SYSTOHC:
- return from_sys_clock ( utc );
-
- case HCTOSYS:
- return to_sys_clock ( utc );
+ opt_complementary = "r--ws:w--rs:s--wr:l--u:u--l";
+ opt = getopt32(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 = rtc_adjtime_is_utc();
+
+ if (opt & HWCLOCK_OPT_HCTOSYS)
+ to_sys_clock(utc);
+ else if (opt & HWCLOCK_OPT_SYSTOHC)
+ from_sys_clock(utc);
+ else
+ /* default HWCLOCK_OPT_SHOW */
+ show_clock(utc);
- case SHOW:
- default:
- return show_clock ( utc );
- }
+ return 0;
}
-
-
diff --git a/release/src/router/busybox/util-linux/ipcrm.c b/release/src/router/busybox/util-linux/ipcrm.c
new file mode 100644
index 00000000..5dcda859
--- /dev/null
+++ b/release/src/router/busybox/util-linux/ipcrm.c
@@ -0,0 +1,220 @@
+/* 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 "libbb.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 *array;
+ struct seminfo *__buf;
+};
+#endif
+
+#define IPCRM_LEGACY 1
+
+
+#if IPCRM_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 /* IPCRM_LEGACY */
+
+
+int ipcrm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+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;
+#if IPCRM_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(EXIT_FAILURE);
+ printf("resource(s) deleted\n");
+ return 0;
+ }
+ }
+#endif /* IPCRM_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;
+
+ 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, "key", 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/release/src/router/busybox/util-linux/ipcs.c b/release/src/router/busybox/util-linux/ipcs.c
new file mode 100644
index 00000000..92012570
--- /dev/null
+++ b/release/src/router/busybox/util-linux/ipcs.c
@@ -0,0 +1,621 @@
+/* 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.
+ */
+
+/* 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>
+
+#include "libbb.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 *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);
+
+ pw = getpwuid(ipcp->cuid);
+ if (pw) printf(" %-10s", pw->pw_name);
+ else printf(" %-10d", ipcp->cuid);
+ gr = getgrgid(ipcp->cgid);
+ if (gr) printf(" %-10s", gr->gr_name);
+ else printf(" %-10d", ipcp->cgid);
+
+ pw = getpwuid(ipcp->uid);
+ if (pw) printf(" %-10s", pw->pw_name);
+ else printf(" %-10d", ipcp->uid);
+ gr = getgrgid(ipcp->gid);
+ if (gr) 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);
+ }
+ bb_putchar('\n');
+}
+
+int ipcs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int ipcs_main(int argc UNUSED_PARAM, 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(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(EXIT_SUCCESS);
+ }
+ if (flags & flag_sem) {
+ print_sem(id);
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+ }
+ if (flags & flag_msg) {
+ print_msg(id);
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+ }
+ bb_show_usage();
+ }
+
+ if (!(flags & (flag_shm | flag_msg | flag_sem)))
+ flags |= flag_msg | flag_shm | flag_sem;
+ bb_putchar('\n');
+
+ if (flags & flag_shm) {
+ do_shm();
+ bb_putchar('\n');
+ }
+ if (flags & flag_sem) {
+ do_sem();
+ bb_putchar('\n');
+ }
+ if (flags & flag_msg) {
+ do_msg();
+ bb_putchar('\n');
+ }
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+}
diff --git a/release/src/router/busybox/util-linux/losetup.c b/release/src/router/busybox/util-linux/losetup.c
index c9445652..e224a4d5 100644
--- a/release/src/router/busybox/util-linux/losetup.c
+++ b/release/src/router/busybox/util-linux/losetup.c
@@ -1,59 +1,79 @@
+/* vi: set sw=4 ts=4: */
/*
* Mini losetup implementation for busybox
*
* Copyright (C) 2002 Matt Kraai.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <getopt.h>
-#include <stdlib.h>
+#include "libbb.h"
-#include "busybox.h"
-
-int
-losetup_main (int argc, char **argv)
+int losetup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int losetup_main(int argc, char **argv)
{
- int delete = 0;
- int offset = 0;
- int opt;
-
- while ((opt = getopt (argc, argv, "do:")) != -1)
- switch (opt)
- {
- case 'd':
- delete = 1;
- break;
-
- case 'o':
- offset = bb_xparse_number (optarg, NULL);
- break;
-
- default:
- bb_show_usage();
- }
-
- if ((delete && (offset || optind + 1 != argc))
- || (!delete && optind + 2 != argc))
- bb_show_usage();
-
- opt = 0;
- if (delete)
- return del_loop (argv[optind]) ? EXIT_SUCCESS : EXIT_FAILURE;
- else
- return set_loop (argv[optind], argv[optind + 1], offset, &opt)
- ? EXIT_FAILURE : EXIT_SUCCESS;
+ char dev[] = LOOP_NAME"0";
+ unsigned opt;
+ char *opt_o;
+ char *s;
+ unsigned long long offset = 0;
+
+ /* max 2 args, all opts are mutually exclusive */
+ opt_complementary = "?2:d--of:o--df:f-do";
+ opt = getopt32(argv, "do:f", &opt_o);
+ argc -= optind;
+ argv += optind;
+
+ if (opt == 0x2) // -o
+ offset = xatoull(opt_o);
+
+ if (opt == 0x4 && argc) // -f does not take any argument
+ bb_show_usage();
+
+ if (opt == 0x1) { // -d
+ /* detach takes exactly one argument */
+ if (argc != 1)
+ bb_show_usage();
+ if (del_loop(argv[0]))
+ bb_simple_perror_msg_and_die(argv[0]);
+ return EXIT_SUCCESS;
+ }
+
+ if (argc == 2) {
+ /* -o or no option */
+ if (set_loop(&argv[0], argv[1], offset) < 0)
+ bb_simple_perror_msg_and_die(argv[0]);
+ return EXIT_SUCCESS;
+ }
+
+ if (argc == 1) {
+ /* -o or no option */
+ s = query_loop(argv[0]);
+ if (!s)
+ bb_simple_perror_msg_and_die(argv[0]);
+ printf("%s: %s\n", argv[0], s);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(s);
+ return EXIT_SUCCESS;
+ }
+
+ /* -o, -f or no option */
+ while (1) {
+ s = query_loop(dev);
+ if (!s) {
+ if (opt == 0x4) {
+ puts(dev);
+ return EXIT_SUCCESS;
+ }
+ } else {
+ if (opt != 0x4)
+ printf("%s: %s\n", dev, s);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(s);
+ }
+
+ if (++dev[sizeof(dev) - 2] > '9')
+ break;
+ }
+ return EXIT_SUCCESS;
}
diff --git a/release/src/router/busybox/util-linux/mdev.c b/release/src/router/busybox/util-linux/mdev.c
new file mode 100644
index 00000000..3c4540cf
--- /dev/null
+++ b/release/src/router/busybox/util-linux/mdev.c
@@ -0,0 +1,544 @@
+/* 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 "libbb.h"
+#include "xregex.h"
+
+struct globals {
+ int root_major, root_minor;
+ char *subsystem;
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define root_major (G.root_major)
+#define root_minor (G.root_minor)
+#define subsystem (G.subsystem)
+
+/* Prevent infinite loops in /sys symlinks */
+#define MAX_SYSFS_DEPTH 3
+
+/* We use additional 64+ bytes in make_device() */
+#define SCRATCH_SIZE 80
+
+#if ENABLE_FEATURE_MDEV_RENAME
+/* Builds an alias path.
+ * This function potentionally reallocates the alias parameter.
+ */
+static char *build_alias(char *alias, const char *device_name)
+{
+ char *dest;
+
+ /* ">bar/": rename to bar/device_name */
+ /* ">bar[/]baz": rename to bar[/]baz */
+ dest = strrchr(alias, '/');
+ if (dest) { /* ">bar/[baz]" ? */
+ *dest = '\0'; /* mkdir bar */
+ bb_make_directory(alias, 0755, FILEUTILS_RECUR);
+ *dest = '/';
+ if (dest[1] == '\0') { /* ">bar/" => ">bar/device_name" */
+ dest = alias;
+ alias = concat_path_file(alias, device_name);
+ free(dest);
+ }
+ }
+
+ return alias;
+}
+#endif
+
+/* mknod in /dev based on a path like "/sys/block/hda/hda1" */
+/* NB: "mdev -s" may call us many times, do not leak memory/fds! */
+static void make_device(char *path, int delete)
+{
+#if ENABLE_FEATURE_MDEV_CONF
+ parser_t *parser;
+#endif
+ const char *device_name;
+ int major, minor, type, len;
+ int mode;
+ char *dev_maj_min = path + strlen(path);
+
+ /* Force the configuration file settings exactly. */
+ umask(0);
+
+ /* 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.
+ */
+ major = -1;
+ if (!delete) {
+ strcpy(dev_maj_min, "/dev");
+ len = open_read_close(path, dev_maj_min + 1, 64);
+ *dev_maj_min++ = '\0';
+ if (len < 1) {
+ if (!ENABLE_FEATURE_MDEV_EXEC)
+ return;
+ /* no "dev" file, so just try to run script */
+ *dev_maj_min = '\0';
+ } else if (sscanf(dev_maj_min, "%u:%u", &major, &minor) != 2) {
+ major = -1;
+ }
+ }
+
+ /* Determine device name, type, major and minor */
+ device_name = bb_basename(path);
+ /* http://kernel.org/doc/pending/hotplug.txt says that only
+ * "/sys/block/..." is for block devices. "/sys/bus" etc is not.
+ * But since 2.6.25 block devices are also in /sys/class/block.
+ * We use strstr("/block/") to forestall future surprises. */
+ type = S_IFCHR;
+ if (strstr(path, "/block/"))
+ type = S_IFBLK;
+
+#if !ENABLE_FEATURE_MDEV_CONF
+ mode = 0660;
+#else
+ /* If we have config file, look up user settings */
+ parser = config_open2("/etc/mdev.conf", fopen_for_read);
+ while (1) {
+ regmatch_t off[1 + 9*ENABLE_FEATURE_MDEV_RENAME_REGEXP];
+ int keep_matching;
+ char *val;
+ struct bb_uidgid_t ugid;
+ char *tokens[4];
+# if ENABLE_FEATURE_MDEV_EXEC
+ char *command = NULL;
+# endif
+# if ENABLE_FEATURE_MDEV_RENAME
+ char *alias = NULL;
+ char aliaslink = aliaslink; /* for compiler */
+# endif
+ /* Defaults in case we won't match any line */
+ ugid.uid = ugid.gid = 0;
+ keep_matching = 0;
+ mode = 0660;
+
+ if (!config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL)) {
+ /* End of file, create dev node with default params */
+ goto line_matches;
+ }
+
+ val = tokens[0];
+ keep_matching = ('-' == val[0]);
+ val += keep_matching; /* swallow leading dash */
+
+ /* Fields: regex uid:gid mode [alias] [cmd] */
+
+ /* 1st field: @<numeric maj,min>... */
+ if (val[0] == '@') {
+ /* @major,minor[-last] */
+ /* (useful when name is ambiguous:
+ * "/sys/class/usb/lp0" and
+ * "/sys/class/printer/lp0") */
+ int cmaj, cmin0, cmin1, sc;
+ if (major < 0)
+ continue; /* no dev, no match */
+ sc = sscanf(val, "@%u,%u-%u", &cmaj, &cmin0, &cmin1);
+ if (sc < 1 || major != cmaj
+ || (sc == 2 && minor != cmin0)
+ || (sc == 3 && (minor < cmin0 || minor > cmin1))
+ ) {
+ continue; /* this line doesn't match */
+ }
+ } else { /* ... or regex to match device name */
+ regex_t match;
+ int result;
+ const char *dev_name_or_subsystem = device_name;
+ if ('/' == val[0] && subsystem) {
+ dev_name_or_subsystem = subsystem;
+ val++;
+ }
+
+ /* Is this it? */
+ xregcomp(&match, val, REG_EXTENDED);
+ result = regexec(&match, dev_name_or_subsystem, ARRAY_SIZE(off), off, 0);
+ regfree(&match);
+
+ //bb_error_msg("matches:");
+ //for (int i = 0; i < ARRAY_SIZE(off); i++) {
+ // if (off[i].rm_so < 0) continue;
+ // bb_error_msg("match %d: '%.*s'\n", i,
+ // (int)(off[i].rm_eo - off[i].rm_so),
+ // device_name + off[i].rm_so);
+ //}
+
+ /* If not this device, skip rest of line */
+ /* (regexec returns whole pattern as "range" 0) */
+ if (result || off[0].rm_so
+ || ((int)off[0].rm_eo != (int)strlen(dev_name_or_subsystem))
+ ) {
+ continue; /* this line doesn't match */
+ }
+ }
+
+ /* This line matches: stop parsing the file after parsing
+ * the rest of fields unless keep_matching == 1 */
+
+ /* 2nd field: uid:gid - device ownership */
+ if (get_uidgid(&ugid, tokens[1], 1) == 0)
+ bb_error_msg("unknown user/group %s", tokens[1]);
+
+ /* 3rd field: mode - device permissions */
+ mode = strtoul(tokens[2], NULL, 8);
+
+ val = tokens[3];
+ /* 4th field (opt): >|=alias */
+# if ENABLE_FEATURE_MDEV_RENAME
+ if (!val)
+ goto line_matches;
+ aliaslink = val[0];
+ if (aliaslink == '>' || aliaslink == '=') {
+ char *a, *s, *st;
+# if ENABLE_FEATURE_MDEV_RENAME_REGEXP
+ char *p;
+ unsigned i, n;
+# endif
+ a = val;
+ s = strchrnul(val, ' ');
+ st = strchrnul(val, '\t');
+ if (st < s)
+ s = st;
+ val = (s[0] && s[1]) ? s+1 : NULL;
+ s[0] = '\0';
+
+# if ENABLE_FEATURE_MDEV_RENAME_REGEXP
+ /* substitute %1..9 with off[1..9], if any */
+ n = 0;
+ s = a;
+ while (*s)
+ if (*s++ == '%')
+ n++;
+
+ p = alias = xzalloc(strlen(a) + n * strlen(device_name));
+ s = a + 1;
+ while (*s) {
+ *p = *s;
+ if ('%' == *s) {
+ i = (s[1] - '0');
+ if (i <= 9 && off[i].rm_so >= 0) {
+ n = off[i].rm_eo - off[i].rm_so;
+ strncpy(p, device_name + off[i].rm_so, n);
+ p += n - 1;
+ s++;
+ }
+ }
+ p++;
+ s++;
+ }
+# else
+ alias = xstrdup(a + 1);
+# endif
+ }
+# endif /* ENABLE_FEATURE_MDEV_RENAME */
+
+# if ENABLE_FEATURE_MDEV_EXEC
+ /* The rest (opt): @|$|*command */
+ if (!val)
+ goto line_matches;
+ {
+ const char *s = "@$*";
+ const char *s2 = strchr(s, val[0]);
+
+ if (!s2)
+ bb_error_msg_and_die("bad line %u", parser->lineno);
+
+ /* Correlate the position in the "@$*" with the delete
+ * step so that we get the proper behavior:
+ * @cmd: run on create
+ * $cmd: run on delete
+ * *cmd: run on both
+ */
+ if ((s2 - s + 1) /*1/2/3*/ & /*1/2*/ (1 + delete)) {
+ command = xstrdup(val + 1);
+ }
+ }
+# endif
+ /* End of field parsing */
+ line_matches:
+#endif /* ENABLE_FEATURE_MDEV_CONF */
+
+ /* "Execute" the line we found */
+
+ if (!delete && major >= 0) {
+ if (ENABLE_FEATURE_MDEV_RENAME)
+ unlink(device_name);
+ if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST)
+ bb_perror_msg_and_die("mknod %s", device_name);
+ if (major == root_major && minor == root_minor)
+ symlink(device_name, "root");
+#if ENABLE_FEATURE_MDEV_CONF
+ chown(device_name, ugid.uid, ugid.gid);
+# if ENABLE_FEATURE_MDEV_RENAME
+ if (alias) {
+ alias = build_alias(alias, device_name);
+ /* move the device, and optionally
+ * make a symlink to moved device node */
+ if (rename(device_name, alias) == 0 && aliaslink == '>')
+ symlink(alias, device_name);
+ free(alias);
+ }
+# endif
+#endif
+ }
+#if ENABLE_FEATURE_MDEV_EXEC
+ if (command) {
+ /* setenv will leak memory, use putenv/unsetenv/free */
+ char *s = xasprintf("%s=%s", "MDEV", device_name);
+ char *s1 = xasprintf("%s=%s", "SUBSYSTEM", subsystem);
+ putenv(s);
+ putenv(s1);
+ if (system(command) == -1)
+ bb_perror_msg_and_die("can't run '%s'", command);
+ unsetenv("SUBSYSTEM");
+ free(s1);
+ unsetenv("MDEV");
+ free(s);
+ free(command);
+ }
+#endif
+ if (delete) {
+ unlink(device_name);
+ /* At creation time, device might have been moved
+ * and a symlink might have been created. Undo that. */
+#if ENABLE_FEATURE_MDEV_RENAME
+ if (alias) {
+ alias = build_alias(alias, device_name);
+ unlink(alias);
+ free(alias);
+ }
+#endif
+ }
+
+#if ENABLE_FEATURE_MDEV_CONF
+ /* We found matching line.
+ * Stop unless it was prefixed with '-' */
+ if (!keep_matching)
+ break;
+ } /* end of "while line is read from /etc/mdev.conf" */
+
+ config_close(parser);
+#endif /* ENABLE_FEATURE_MDEV_CONF */
+}
+
+/* File callback for /sys/ traversal */
+static int FAST_FUNC fileAction(const char *fileName,
+ struct stat *statbuf UNUSED_PARAM,
+ void *userData,
+ int depth UNUSED_PARAM)
+{
+ size_t len = strlen(fileName) - 4; /* can't underflow */
+ char *scratch = userData;
+
+ /* len check is for paranoid reasons */
+ if (strcmp(fileName + len, "/dev") != 0 || len >= PATH_MAX)
+ return FALSE;
+
+ strcpy(scratch, fileName);
+ scratch[len] = '\0';
+ make_device(scratch, 0);
+
+ return TRUE;
+}
+
+/* Directory callback for /sys/ traversal */
+static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM,
+ struct stat *statbuf UNUSED_PARAM,
+ void *userData UNUSED_PARAM,
+ int depth)
+{
+ /* Extract device subsystem -- the name of the directory
+ * under /sys/class/ */
+ if (1 == depth) {
+ free(subsystem);
+ subsystem = strrchr(fileName, '/');
+ if (subsystem)
+ subsystem = xstrdup(subsystem + 1);
+ }
+
+ return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE);
+}
+
+/* For the full gory details, see linux/Documentation/firmware_class/README
+ *
+ * Firmware loading works like this:
+ * - kernel sets FIRMWARE env var
+ * - userspace checks /lib/firmware/$FIRMWARE
+ * - userspace waits for /sys/$DEVPATH/loading to appear
+ * - userspace writes "1" to /sys/$DEVPATH/loading
+ * - userspace copies /lib/firmware/$FIRMWARE into /sys/$DEVPATH/data
+ * - userspace writes "0" (worked) or "-1" (failed) to /sys/$DEVPATH/loading
+ * - kernel loads firmware into device
+ */
+static void load_firmware(const char *const firmware, const char *const sysfs_path)
+{
+ int cnt;
+ int firmware_fd, loading_fd, data_fd;
+
+ /* check for /lib/firmware/$FIRMWARE */
+ xchdir("/lib/firmware");
+ firmware_fd = xopen(firmware, O_RDONLY);
+
+ /* in case we goto out ... */
+ data_fd = -1;
+
+ /* check for /sys/$DEVPATH/loading ... give 30 seconds to appear */
+ xchdir(sysfs_path);
+ for (cnt = 0; cnt < 30; ++cnt) {
+ loading_fd = open("loading", O_WRONLY);
+ if (loading_fd != -1)
+ goto loading;
+ sleep(1);
+ }
+ goto out;
+
+ loading:
+ /* tell kernel we're loading by "echo 1 > /sys/$DEVPATH/loading" */
+ if (full_write(loading_fd, "1", 1) != 1)
+ goto out;
+
+ /* load firmware into /sys/$DEVPATH/data */
+ data_fd = open("data", O_WRONLY);
+ if (data_fd == -1)
+ goto out;
+ cnt = bb_copyfd_eof(firmware_fd, data_fd);
+
+ /* tell kernel result by "echo [0|-1] > /sys/$DEVPATH/loading" */
+ if (cnt > 0)
+ full_write(loading_fd, "0", 1);
+ else
+ full_write(loading_fd, "-1", 2);
+
+ out:
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ close(firmware_fd);
+ close(loading_fd);
+ close(data_fd);
+ }
+}
+
+int mdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mdev_main(int argc UNUSED_PARAM, char **argv)
+{
+ RESERVE_CONFIG_BUFFER(temp, PATH_MAX + SCRATCH_SIZE);
+
+ /* We can be called as hotplug helper */
+ /* Kernel cannot provide suitable stdio fds for us, do it ourself */
+#if 1
+ bb_sanitize_stdio();
+#else
+ /* Debug code */
+ /* Replace LOGFILE by other file or device name if you need */
+#define LOGFILE "/dev/console"
+ /* Just making sure fd 0 is not closed,
+ * we don't really intend to read from it */
+ xmove_fd(xopen("/", O_RDONLY), STDIN_FILENO);
+ xmove_fd(xopen(LOGFILE, O_WRONLY|O_APPEND), STDOUT_FILENO);
+ xmove_fd(xopen(LOGFILE, O_WRONLY|O_APPEND), STDERR_FILENO);
+#endif
+
+ xchdir("/dev");
+
+ if (argv[1] && strcmp(argv[1], "-s") == 0) {
+ /* Scan:
+ * mdev -s
+ */
+ struct stat st;
+
+ xstat("/", &st);
+ root_major = major(st.st_dev);
+ root_minor = minor(st.st_dev);
+
+ /* ACTION_FOLLOWLINKS is needed since in newer kernels
+ * /sys/block/loop* (for example) are symlinks to dirs,
+ * not real directories.
+ * (kernel's CONFIG_SYSFS_DEPRECATED makes them real dirs,
+ * but we can't enforce that on users)
+ */
+ if (access("/sys/class/block", F_OK) != 0) {
+ /* Scan obsolete /sys/block only if /sys/class/block
+ * doesn't exist. Otherwise we'll have dupes.
+ * Also, do not complain if it doesn't exist.
+ * Some people configure kernel to have no blockdevs.
+ */
+ recursive_action("/sys/block",
+ ACTION_RECURSE | ACTION_FOLLOWLINKS | ACTION_QUIET,
+ fileAction, dirAction, temp, 0);
+ }
+ recursive_action("/sys/class",
+ ACTION_RECURSE | ACTION_FOLLOWLINKS,
+ fileAction, dirAction, temp, 0);
+ } else {
+ char *fw;
+ char *seq;
+ char *action;
+ char *env_path;
+
+ /* Hotplug:
+ * env ACTION=... DEVPATH=... SUBSYSTEM=... [SEQNUM=...] mdev
+ * ACTION can be "add" or "remove"
+ * DEVPATH is like "/block/sda" or "/class/input/mice"
+ */
+ action = getenv("ACTION");
+ env_path = getenv("DEVPATH");
+ subsystem = getenv("SUBSYSTEM");
+ if (!action || !env_path /*|| !subsystem*/)
+ bb_show_usage();
+ fw = getenv("FIRMWARE");
+
+ /* If it exists, does /dev/mdev.seq match $SEQNUM?
+ * If it does not match, earlier mdev is running
+ * in parallel, and we need to wait */
+ seq = getenv("SEQNUM");
+ if (seq) {
+ int timeout = 2000 / 32; /* 2000 msec */
+ do {
+ int seqlen;
+ char seqbuf[sizeof(int)*3 + 2];
+
+ seqlen = open_read_close("mdev.seq", seqbuf, sizeof(seqbuf-1));
+ if (seqlen < 0) {
+ seq = NULL;
+ break;
+ }
+ seqbuf[seqlen] = '\0';
+ if (seqbuf[0] == '\n' /* seed file? */
+ || strcmp(seq, seqbuf) == 0 /* correct idx? */
+ ) {
+ break;
+ }
+ usleep(32*1000);
+ } while (--timeout);
+ }
+
+ snprintf(temp, PATH_MAX, "/sys%s", env_path);
+ if (strcmp(action, "remove") == 0) {
+ /* Ignoring "remove firmware". It was reported
+ * to happen and to cause erroneous deletion
+ * of device nodes. */
+ if (!fw)
+ make_device(temp, 1);
+ }
+ else if (strcmp(action, "add") == 0) {
+ make_device(temp, 0);
+ if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) {
+ if (fw)
+ load_firmware(fw, temp);
+ }
+ }
+
+ if (seq) {
+ xopen_xwrite_close("mdev.seq", utoa(xatou(seq) + 1));
+ }
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ RELEASE_CONFIG_BUFFER(temp);
+
+ return EXIT_SUCCESS;
+}
diff --git a/release/src/router/busybox/util-linux/minix.h b/release/src/router/busybox/util-linux/minix.h
new file mode 100644
index 00000000..3e2b989e
--- /dev/null
+++ b/release/src/router/busybox/util-linux/minix.h
@@ -0,0 +1,98 @@
+/*
+ * 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 superblock data on disk
+ */
+struct minix_superblock {
+ 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),
+};
+
+/*
+Basic test script for regressions in mkfs/fsck.
+Copies current dir into image (typically bbox build tree).
+
+#!/bin/sh
+tmpdir=/tmp/minixtest-$$
+tmpimg=/tmp/minix-img-$$
+
+mkdir $tmpdir
+dd if=/dev/zero of=$tmpimg bs=1M count=20 || exit
+./busybox mkfs.minix $tmpimg || exit
+mount -o loop $tmpimg $tmpdir || exit
+cp -a "$PWD" $tmpdir
+umount $tmpdir || exit
+./busybox fsck.minix -vfm $tmpimg || exit
+echo "Continue?"
+read junk
+./busybox fsck.minix -vfml $tmpimg || exit
+rmdir $tmpdir
+rm $tmpimg
+
+*/
diff --git a/release/src/router/busybox/util-linux/mkfs_minix.c b/release/src/router/busybox/util-linux/mkfs_minix.c
index 75a909e6..18512a39 100644
--- a/release/src/router/busybox/util-linux/mkfs_minix.c
+++ b/release/src/router/busybox/util-linux/mkfs_minix.c
@@ -2,8 +2,9 @@
/*
* mkfs.c - make a linux (minix) file-system.
*
- * (C) 1991 Linus Torvalds. This file may be redistributed as per
- * the Linux copyright.
+ * (C) 1991 Linus Torvalds.
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
/*
@@ -33,9 +34,9 @@
* 03.01.94 - Added support for file system valid flag.
* (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu)
*
- * 30.10.94 - added support for v2 filesystem
- * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
- *
+ * 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)
@@ -49,246 +50,162 @@
*
* Usage: mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks]
*
- * -c for readablility checking (SLOW!)
+ * -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 :-).
+ * 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 <stdio.h>
-#include <time.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#include <sys/param.h>
+#include "libbb.h"
#include <mntent.h>
-#include "busybox.h"
-
-#define MINIX_ROOT_INO 1
-#define MINIX_LINK_MAX 250
-#define MINIX2_LINK_MAX 65530
-
-#define MINIX_I_MAP_SLOTS 8
-#define MINIX_Z_MAP_SLOTS 64
-#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
-#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
-#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */
-#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */
-#define MINIX_VALID_FS 0x0001 /* Clean fs. */
-#define MINIX_ERROR_FS 0x0002 /* fs has errors. */
-
-#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
-#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
-
-#define MINIX_V1 0x0001 /* original minix fs */
-#define MINIX_V2 0x0002 /* minix V2 fs */
-
-#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version
-
-/*
- * This is the original minix inode layout on disk.
- * Note the 8-bit gid and atime and ctime.
- */
-struct minix_inode {
- u_int16_t i_mode;
- u_int16_t i_uid;
- u_int32_t i_size;
- u_int32_t i_time;
- u_int8_t i_gid;
- u_int8_t i_nlinks;
- u_int16_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 {
- u_int16_t i_mode;
- u_int16_t i_nlinks;
- u_int16_t i_uid;
- u_int16_t i_gid;
- u_int32_t i_size;
- u_int32_t i_atime;
- u_int32_t i_mtime;
- u_int32_t i_ctime;
- u_int32_t i_zone[10];
-};
+#include "minix.h"
-/*
- * minix super-block data on disk
- */
-struct minix_super_block {
- u_int16_t s_ninodes;
- u_int16_t s_nzones;
- u_int16_t s_imap_blocks;
- u_int16_t s_zmap_blocks;
- u_int16_t s_firstdatazone;
- u_int16_t s_log_zone_size;
- u_int32_t s_max_size;
- u_int16_t s_magic;
- u_int16_t s_state;
- u_int32_t s_zones;
-};
+/* Store the very same times/uids/gids for image consistency */
+#if 1
+# define CUR_TIME 0
+# define GETUID 0
+# define GETGID 0
+#else
+/* Was using this. Is it useful? NB: this will break testsuite */
+# define CUR_TIME time(NULL)
+# define GETUID getuid()
+# define GETGID getgid()
+#endif
-struct minix_dir_entry {
- u_int16_t inode;
- char name[0];
+enum {
+ MAX_GOOD_BLOCKS = 512,
+ TEST_BUFFER_BLOCKS = 16,
};
-#define BLOCK_SIZE_BITS 10
-#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
-
-#define NAME_MAX 255 /* # chars in a file name */
-
-#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
-
-#define MINIX_VALID_FS 0x0001 /* Clean fs. */
-#define MINIX_ERROR_FS 0x0002 /* fs has errors. */
+#if !ENABLE_FEATURE_MINIX2
+enum { version2 = 0 };
+#endif
-#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
-#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
+enum { dev_fd = 3 };
-#ifndef BLKGETSIZE
-#define BLKGETSIZE _IO(0x12,96) /* return device size */
+struct globals {
+#if ENABLE_FEATURE_MINIX2
+ smallint 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 superblock_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];
+
+ unsigned short ind_block1[BLOCK_SIZE >> 1];
+ unsigned short dind_block1[BLOCK_SIZE >> 1];
+ unsigned long ind_block2[BLOCK_SIZE >> 2];
+ unsigned long dind_block2[BLOCK_SIZE >> 2];
+};
+#define G (*ptr_to_globals)
+#define INIT_G() do { \
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+} while (0)
+static ALWAYS_INLINE unsigned div_roundup(unsigned size, unsigned n)
+{
+ return (size + n-1) / n;
+}
-#ifndef __linux__
-#define volatile
-#endif
+#define INODE_BUF1 (((struct minix1_inode*)G.inode_buffer) - 1)
+#define INODE_BUF2 (((struct minix2_inode*)G.inode_buffer) - 1)
-#define MINIX_ROOT_INO 1
-#define MINIX_BAD_INO 2
+#define SB (*(struct minix_superblock*)G.superblock_buffer)
-#define TEST_BUFFER_BLOCKS 16
-#define MAX_GOOD_BLOCKS 512
+#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)
-#define UPPER(size,n) (((size)+((n)-1))/(n))
-#define INODE_SIZE (sizeof(struct minix_inode))
-#ifdef CONFIG_FEATURE_MINIX2
-#define INODE_SIZE2 (sizeof(struct minix2_inode))
-#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
- : MINIX_INODES_PER_BLOCK))
+#if !ENABLE_FEATURE_MINIX2
+# define SB_ZONES (SB.s_nzones)
+# define INODE_BLOCKS div_roundup(SB_INODES, MINIX1_INODES_PER_BLOCK)
#else
-#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK))
+# 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 BITS_PER_BLOCK (BLOCK_SIZE<<3)
-
-static char *device_name = NULL;
-static int DEV = -1;
-static long BLOCKS = 0;
-static int check = 0;
-static int badblocks = 0;
-static int namelen = 30; /* default (changed to 30, per Linus's
-
- suggestion, Sun Nov 21 08:05:07 1993) */
-static int dirsize = 32;
-static int magic = MINIX_SUPER_MAGIC2;
-static int version2 = 0;
-static char root_block[BLOCK_SIZE] = "\0";
+#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
+#define NORM_FIRSTZONE (2 + SB_IMAPS + SB_ZMAPS + INODE_BLOCKS)
-static char *inode_buffer = NULL;
+/* Before you ask "where they come from?": */
+/* setbit/clrbit are supplied by sys/param.h */
-#define Inode (((struct minix_inode *) inode_buffer)-1)
-#ifdef CONFIG_FEATURE_MINIX2
-#define Inode2 (((struct minix2_inode *) inode_buffer)-1)
-#endif
-static char super_block_buffer[BLOCK_SIZE];
-static char boot_block_buffer[512];
-
-#define Super (*(struct minix_super_block *)super_block_buffer)
-#define INODES ((unsigned long)Super.s_ninodes)
-#ifdef CONFIG_FEATURE_MINIX2
-#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones))
-#else
-#define ZONES ((unsigned long)(Super.s_nzones))
-#endif
-#define IMAPS ((unsigned long)Super.s_imap_blocks)
-#define ZMAPS ((unsigned long)Super.s_zmap_blocks)
-#define FIRSTZONE ((unsigned long)Super.s_firstdatazone)
-#define ZONESIZE ((unsigned long)Super.s_log_zone_size)
-#define MAXSIZE ((unsigned long)Super.s_max_size)
-#define MAGIC (Super.s_magic)
-#define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS)
-
-static char *inode_map;
-static char *zone_map;
-
-static unsigned short good_blocks_table[MAX_GOOD_BLOCKS];
-static int used_good_blocks = 0;
-static unsigned long req_nr_inodes = 0;
-
-static inline int bit(char * a,unsigned int i)
+static int minix_bit(const char* a, unsigned i)
{
- return (a[i >> 3] & (1<<(i & 7))) != 0;
+ return a[i >> 3] & (1<<(i & 7));
}
-#define inode_in_use(x) (bit(inode_map,(x)))
-#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1))
-#define mark_inode(x) (setbit(inode_map,(x)))
-#define unmark_inode(x) (clrbit(inode_map,(x)))
+static void minix_setbit(char *a, unsigned i)
+{
+ setbit(a, i);
+}
+static void minix_clrbit(char *a, unsigned i)
+{
+ clrbit(a, i);
+}
-#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1))
-#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1))
+/* 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))*/
-/*
- * Check to make certain that our new filesystem won't be created on
- * an already mounted partition. Code adapted from mke2fs, Copyright
- * (C) 1994 Theodore Ts'o. Also licensed under GPL.
- */
-extern inline void check_mount(void)
-{
- FILE *f;
- struct mntent *mnt;
+#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)
- if ((f = setmntent(MOUNTED, "r")) == NULL)
- return;
- while ((mnt = getmntent(f)) != NULL)
- if (strcmp(device_name, mnt->mnt_fsname) == 0)
- break;
- endmntent(f);
- if (!mnt)
- return;
+#ifndef BLKGETSIZE
+# define BLKGETSIZE _IO(0x12,96) /* return device size */
+#endif
- bb_error_msg_and_die("%s is mounted; will not make a filesystem here!", device_name);
-}
static long valid_offset(int fd, int offset)
{
char ch;
- if (lseek(fd, offset, 0) < 0)
+ if (lseek(fd, offset, SEEK_SET) < 0)
return 0;
if (read(fd, &ch, 1) < 1)
return 0;
return 1;
}
-extern inline int count_blocks(int fd)
+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;
@@ -301,13 +218,12 @@ extern inline int count_blocks(int fd)
return (low + 1);
}
-extern inline int get_size(const char *file)
+static int get_size(const char *file)
{
int fd;
long size;
- if ((fd = open(file, O_RDWR)) < 0)
- bb_perror_msg_and_die("%s", file);
+ fd = xopen(file, O_RDWR);
if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
close(fd);
return (size * 512);
@@ -318,91 +234,102 @@ extern inline int get_size(const char *file)
return size;
}
-extern inline void write_tables(void)
+static void write_tables(void)
{
- /* Mark the super block valid. */
- Super.s_state |= MINIX_VALID_FS;
- Super.s_state &= ~MINIX_ERROR_FS;
-
- if (lseek(DEV, 0, SEEK_SET))
- bb_error_msg_and_die("seek to boot block failed in write_tables");
- if (512 != write(DEV, boot_block_buffer, 512))
- bb_error_msg_and_die("unable to clear boot sector");
- if (BLOCK_SIZE != lseek(DEV, BLOCK_SIZE, SEEK_SET))
- bb_error_msg_and_die("seek failed in write_tables");
- if (BLOCK_SIZE != write(DEV, super_block_buffer, BLOCK_SIZE))
- bb_error_msg_and_die("unable to write super-block");
- if (IMAPS * BLOCK_SIZE != write(DEV, inode_map, IMAPS * BLOCK_SIZE))
- bb_error_msg_and_die("unable to write inode map");
- if (ZMAPS * BLOCK_SIZE != write(DEV, zone_map, ZMAPS * BLOCK_SIZE))
- bb_error_msg_and_die("unable to write zone map");
- if (INODE_BUFFER_SIZE != write(DEV, inode_buffer, INODE_BUFFER_SIZE))
- bb_error_msg_and_die("unable to write inodes");
+ /* Mark the superblock valid. */
+ SB.s_state |= MINIX_VALID_FS;
+ SB.s_state &= ~MINIX_ERROR_FS;
+
+ msg_eol = "seek to 0 failed";
+ xlseek(dev_fd, 0, SEEK_SET);
+
+ msg_eol = "cannot clear boot sector";
+ xwrite(dev_fd, G.boot_block_buffer, 512);
+
+ msg_eol = "seek to BLOCK_SIZE failed";
+ xlseek(dev_fd, BLOCK_SIZE, SEEK_SET);
+
+ msg_eol = "cannot write superblock";
+ xwrite(dev_fd, G.superblock_buffer, BLOCK_SIZE);
+
+ msg_eol = "cannot write inode map";
+ xwrite(dev_fd, G.inode_map, SB_IMAPS * BLOCK_SIZE);
+
+ msg_eol = "cannot write zone map";
+ xwrite(dev_fd, G.zone_map, SB_ZMAPS * BLOCK_SIZE);
+
+ msg_eol = "cannot write inodes";
+ xwrite(dev_fd, G.inode_buffer, INODE_BUFFER_SIZE);
+ msg_eol = "\n";
}
static void write_block(int blk, char *buffer)
{
- if (blk * BLOCK_SIZE != lseek(DEV, blk * BLOCK_SIZE, SEEK_SET))
- bb_error_msg_and_die("seek failed in write_block");
- if (BLOCK_SIZE != write(DEV, buffer, BLOCK_SIZE))
- bb_error_msg_and_die("write failed in write_block");
+ xlseek(dev_fd, blk * BLOCK_SIZE, SEEK_SET);
+ xwrite(dev_fd, buffer, BLOCK_SIZE);
}
static int get_free_block(void)
{
int blk;
- if (used_good_blocks + 1 >= MAX_GOOD_BLOCKS)
+ if (G.used_good_blocks + 1 >= MAX_GOOD_BLOCKS)
bb_error_msg_and_die("too many bad blocks");
- if (used_good_blocks)
- blk = good_blocks_table[used_good_blocks - 1] + 1;
+ if (G.used_good_blocks)
+ blk = G.good_blocks_table[G.used_good_blocks - 1] + 1;
else
- blk = FIRSTZONE;
- while (blk < ZONES && zone_in_use(blk))
+ blk = SB_FIRSTZONE;
+ while (blk < SB_ZONES && zone_in_use(blk))
blk++;
- if (blk >= ZONES)
+ if (blk >= SB_ZONES)
bb_error_msg_and_die("not enough good blocks");
- good_blocks_table[used_good_blocks] = blk;
- used_good_blocks++;
+ G.good_blocks_table[G.used_good_blocks] = blk;
+ G.used_good_blocks++;
return blk;
}
-extern inline void mark_good_blocks(void)
+static void mark_good_blocks(void)
{
int blk;
- for (blk = 0; blk < used_good_blocks; blk++)
- mark_zone(good_blocks_table[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 = FIRSTZONE - 1;
- while (++zone < ZONES)
+ zone = SB_FIRSTZONE - 1;
+ while (++zone < SB_ZONES)
if (zone_in_use(zone))
return zone;
return 0;
}
-extern inline void make_bad_inode(void)
+static void make_bad_inode(void)
{
- struct minix_inode *inode = &Inode[MINIX_BAD_INO];
+ struct minix1_inode *inode = &INODE_BUF1[MINIX_BAD_INO];
int i, j, zone;
int ind = 0, dind = 0;
+ /* moved to globals to reduce stack usage
unsigned short ind_block[BLOCK_SIZE >> 1];
unsigned short dind_block[BLOCK_SIZE >> 1];
+ */
+#define ind_block (G.ind_block1)
+#define dind_block (G.dind_block1)
#define NEXT_BAD (zone = next(zone))
- if (!badblocks)
+ if (!G.badblocks)
return;
mark_inode(MINIX_BAD_INO);
inode->i_nlinks = 1;
- inode->i_time = time(NULL);
+ /* 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 = badblocks * BLOCK_SIZE;
+ inode->i_size = G.badblocks * BLOCK_SIZE;
zone = next(0);
for (i = 0; i < 7; i++) {
inode->i_zone[i] = zone;
@@ -429,29 +356,35 @@ extern inline void make_bad_inode(void)
}
}
bb_error_msg_and_die("too many bad blocks");
- end_bad:
+ end_bad:
if (ind)
write_block(ind, (char *) ind_block);
if (dind)
write_block(dind, (char *) dind_block);
+#undef ind_block
+#undef dind_block
}
-#ifdef CONFIG_FEATURE_MINIX2
-extern inline void make_bad_inode2(void)
+#if ENABLE_FEATURE_MINIX2
+static void make_bad_inode2(void)
{
- struct minix2_inode *inode = &Inode2[MINIX_BAD_INO];
+ struct minix2_inode *inode = &INODE_BUF2[MINIX_BAD_INO];
int i, j, zone;
int ind = 0, dind = 0;
+ /* moved to globals to reduce stack usage
unsigned long ind_block[BLOCK_SIZE >> 2];
unsigned long dind_block[BLOCK_SIZE >> 2];
+ */
+#define ind_block (G.ind_block2)
+#define dind_block (G.dind_block2)
- if (!badblocks)
+ if (!G.badblocks)
return;
mark_inode(MINIX_BAD_INO);
inode->i_nlinks = 1;
- inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL);
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CUR_TIME;
inode->i_mode = S_IFREG + 0000;
- inode->i_size = badblocks * BLOCK_SIZE;
+ inode->i_size = G.badblocks * BLOCK_SIZE;
zone = next(0);
for (i = 0; i < 7; i++) {
inode->i_zone[i] = zone;
@@ -479,195 +412,128 @@ extern inline void make_bad_inode2(void)
}
/* Could make triple indirect block here */
bb_error_msg_and_die("too many bad blocks");
- end_bad:
+ end_bad:
if (ind)
write_block(ind, (char *) ind_block);
if (dind)
write_block(dind, (char *) dind_block);
+#undef ind_block
+#undef dind_block
}
+#else
+void make_bad_inode2(void);
#endif
-extern inline void make_root_inode(void)
+static void make_root_inode(void)
{
- struct minix_inode *inode = &Inode[MINIX_ROOT_INO];
+ 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 = time(NULL);
- if (badblocks)
- inode->i_size = 3 * dirsize;
+ inode->i_time = CUR_TIME;
+ if (G.badblocks)
+ inode->i_size = 3 * G.dirsize;
else {
- root_block[2 * dirsize] = '\0';
- root_block[2 * dirsize + 1] = '\0';
- inode->i_size = 2 * dirsize;
+ 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();
+ inode->i_uid = GETUID;
if (inode->i_uid)
- inode->i_gid = getgid();
- write_block(inode->i_zone[0], root_block);
+ inode->i_gid = GETGID;
+ write_block(inode->i_zone[0], G.root_block);
}
-#ifdef CONFIG_FEATURE_MINIX2
-extern inline void make_root_inode2(void)
+#if ENABLE_FEATURE_MINIX2
+static void make_root_inode2(void)
{
- struct minix2_inode *inode = &Inode2[MINIX_ROOT_INO];
+ 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 = time(NULL);
- if (badblocks)
- inode->i_size = 3 * dirsize;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CUR_TIME;
+ if (G.badblocks)
+ inode->i_size = 3 * G.dirsize;
else {
- root_block[2 * dirsize] = '\0';
- root_block[2 * dirsize + 1] = '\0';
- inode->i_size = 2 * dirsize;
+ 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();
+ inode->i_uid = GETUID;
if (inode->i_uid)
- inode->i_gid = getgid();
- write_block(inode->i_zone[0], root_block);
+ inode->i_gid = GETGID;
+ write_block(inode->i_zone[0], G.root_block);
}
+#else
+void make_root_inode2(void);
#endif
-extern inline void setup_tables(void)
-{
- int i;
- unsigned long inodes;
-
- memset(super_block_buffer, 0, BLOCK_SIZE);
- memset(boot_block_buffer, 0, 512);
- MAGIC = magic;
- ZONESIZE = 0;
- MAXSIZE = version2 ? 0x7fffffff : (7 + 512 + 512 * 512) * 1024;
- ZONES = BLOCKS;
-/* some magic nrs: 1 inode / 3 blocks */
- if (req_nr_inodes == 0)
- inodes = BLOCKS / 3;
- else
- inodes = req_nr_inodes;
- /* Round up inode count to fill block size */
-#ifdef CONFIG_FEATURE_MINIX2
- if (version2)
- inodes = ((inodes + MINIX2_INODES_PER_BLOCK - 1) &
- ~(MINIX2_INODES_PER_BLOCK - 1));
- else
-#endif
- inodes = ((inodes + MINIX_INODES_PER_BLOCK - 1) &
- ~(MINIX_INODES_PER_BLOCK - 1));
- if (inodes > 65535)
- inodes = 65535;
- INODES = inodes;
- IMAPS = UPPER(INODES + 1, BITS_PER_BLOCK);
- ZMAPS = 0;
- i = 0;
- while (ZMAPS !=
- UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1,
- BITS_PER_BLOCK) && i < 1000) {
- ZMAPS =
- UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1,
- BITS_PER_BLOCK);
- i++;
- }
- /* 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
- * /sbin/mkfs.minix -i 200 test.fs
- * */
- if (i >= 999) {
- bb_error_msg_and_die("unable to allocate buffers for maps");
- }
- FIRSTZONE = NORM_FIRSTZONE;
- inode_map = xmalloc(IMAPS * BLOCK_SIZE);
- zone_map = xmalloc(ZMAPS * BLOCK_SIZE);
- memset(inode_map, 0xff, IMAPS * BLOCK_SIZE);
- memset(zone_map, 0xff, ZMAPS * BLOCK_SIZE);
- for (i = FIRSTZONE; i < ZONES; i++)
- unmark_zone(i);
- for (i = MINIX_ROOT_INO; i <= INODES; i++)
- unmark_inode(i);
- inode_buffer = xmalloc(INODE_BUFFER_SIZE);
- memset(inode_buffer, 0, INODE_BUFFER_SIZE);
- printf("%ld inodes\n", INODES);
- printf("%ld blocks\n", ZONES);
- printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE);
- printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE);
- printf("Maxsize=%ld\n\n", MAXSIZE);
-}
-
/*
* Perform a test of a block; return the number of
- * blocks readable/writeable.
+ * blocks readable.
*/
-extern inline long do_check(char *buffer, int try, unsigned int current_block)
+static size_t do_check(char *buffer, size_t try, unsigned current_block)
{
- long got;
+ ssize_t got;
/* Seek to the correct loc. */
- if (lseek(DEV, current_block * BLOCK_SIZE, SEEK_SET) !=
- current_block * BLOCK_SIZE) {
- bb_error_msg_and_die("seek failed during testing of blocks");
- }
-
+ msg_eol = "seek failed during testing of blocks";
+ xlseek(dev_fd, current_block * BLOCK_SIZE, SEEK_SET);
+ msg_eol = "\n";
/* Try the read */
- got = read(DEV, buffer, try * BLOCK_SIZE);
+ got = read(dev_fd, buffer, try * BLOCK_SIZE);
if (got < 0)
got = 0;
- if (got & (BLOCK_SIZE - 1)) {
- printf("Weird values in do_check: probably bugs\n");
- }
- got /= BLOCK_SIZE;
- return got;
-}
+ try = ((size_t)got) / BLOCK_SIZE;
-static unsigned int currently_testing = 0;
+ 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)
+static void alarm_intr(int alnum UNUSED_PARAM)
{
- if (currently_testing >= ZONES)
+ if (G.currently_testing >= SB_ZONES)
return;
signal(SIGALRM, alarm_intr);
alarm(5);
- if (!currently_testing)
+ if (!G.currently_testing)
return;
- printf("%d ...", currently_testing);
+ printf("%d ...", G.currently_testing);
fflush(stdout);
}
static void check_blocks(void)
{
- int try, got;
- static char buffer[BLOCK_SIZE * TEST_BUFFER_BLOCKS];
+ size_t try, got;
- currently_testing = 0;
+ G.currently_testing = 0;
signal(SIGALRM, alarm_intr);
alarm(5);
- while (currently_testing < ZONES) {
- if (lseek(DEV, currently_testing * BLOCK_SIZE, SEEK_SET) !=
- currently_testing * BLOCK_SIZE)
- bb_error_msg_and_die("seek failed in check_blocks");
+ while (G.currently_testing < SB_ZONES) {
+ msg_eol = "seek failed in check_blocks";
+ xlseek(dev_fd, G.currently_testing * BLOCK_SIZE, SEEK_SET);
+ msg_eol = "\n";
try = TEST_BUFFER_BLOCKS;
- if (currently_testing + try > ZONES)
- try = ZONES - currently_testing;
- got = do_check(buffer, try, currently_testing);
- currently_testing += got;
+ 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 (currently_testing < FIRSTZONE)
+ if (G.currently_testing < SB_FIRSTZONE)
bb_error_msg_and_die("bad blocks before data-area: cannot make fs");
- mark_zone(currently_testing);
- badblocks++;
- currently_testing++;
+ mark_zone(G.currently_testing);
+ G.badblocks++;
+ G.currently_testing++;
}
- if (badblocks > 1)
- printf("%d bad blocks\n", badblocks);
- else if (badblocks == 1)
- printf("one bad block\n");
+ alarm(0);
+ printf("%d bad block(s)\n", G.badblocks);
}
static void get_list_blocks(char *filename)
@@ -675,171 +541,191 @@ static void get_list_blocks(char *filename)
FILE *listfile;
unsigned long blockno;
- listfile = bb_xfopen(filename, "r");
+ listfile = xfopen_for_read(filename);
while (!feof(listfile)) {
fscanf(listfile, "%ld\n", &blockno);
mark_zone(blockno);
- badblocks++;
+ G.badblocks++;
}
- if (badblocks > 1)
- printf("%d bad blocks\n", badblocks);
- else if (badblocks == 1)
- printf("one bad block\n");
+ 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.superblock_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);
}
-extern int mkfs_minix_main(int argc, char **argv)
+int mkfs_minix_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mkfs_minix_main(int argc UNUSED_PARAM, char **argv)
{
- int i=1;
+ unsigned opt;
char *tmp;
struct stat statbuf;
+ char *str_i;
char *listfile = NULL;
- int stopIt=FALSE;
- if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE)
+ INIT_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");
-#ifdef CONFIG_FEATURE_MINIX2
+#if ENABLE_FEATURE_MINIX2
if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
bb_error_msg_and_die("bad inode size");
#endif
-
- /* Parse options */
- argv++;
- while (--argc >= 0 && *argv && **argv) {
- if (**argv == '-') {
- stopIt=FALSE;
- while (i > 0 && *++(*argv) && stopIt==FALSE) {
- switch (**argv) {
- case 'c':
- check = 1;
- break;
- case 'i':
- {
- char *cp=NULL;
- if (*(*argv+1) != 0) {
- cp = ++(*argv);
- } else {
- if (--argc == 0) {
- goto goodbye;
- }
- cp = *(++argv);
- }
- req_nr_inodes = strtoul(cp, &tmp, 0);
- if (*tmp)
- bb_show_usage();
- stopIt=TRUE;
- break;
- }
- case 'l':
- if (--argc == 0) {
- goto goodbye;
- }
- listfile = *(++argv);
- break;
- case 'n':
- {
- char *cp=NULL;
-
- if (*(*argv+1) != 0) {
- cp = ++(*argv);
- } else {
- if (--argc == 0) {
- goto goodbye;
- }
- cp = *(++argv);
- }
- i = strtoul(cp, &tmp, 0);
- if (*tmp)
- bb_show_usage();
- if (i == 14)
- magic = MINIX_SUPER_MAGIC;
- else if (i == 30)
- magic = MINIX_SUPER_MAGIC2;
- else
- bb_show_usage();
- namelen = i;
- dirsize = i + 2;
- stopIt=TRUE;
- break;
- }
- case 'v':
-#ifdef CONFIG_FEATURE_MINIX2
- version2 = 1;
+
+ opt_complementary = "n+"; /* -n N */
+ opt = getopt32(argv, "ci:l:n:v", &str_i, &listfile, &G.namelen);
+ 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
+ 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("%s: not compiled with minix v2 support",
- device_name);
- exit(-1);
+ bb_error_msg_and_die("not compiled with minix v2 support");
#endif
- break;
- case '-':
- case 'h':
- default:
-goodbye:
- bb_show_usage();
- }
- }
- } else {
- if (device_name == NULL)
- device_name = *argv;
- else if (BLOCKS == 0)
- BLOCKS = strtol(*argv, &tmp, 0);
- else {
- goto goodbye;
- }
- }
- argv++;
}
- if (device_name && !BLOCKS)
- BLOCKS = get_size(device_name) / 1024;
- if (!device_name || BLOCKS < 10) {
+ G.device_name = *argv++;
+ if (!G.device_name)
bb_show_usage();
- }
-#ifdef CONFIG_FEATURE_MINIX2
+ 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) {
- if (namelen == 14)
- magic = MINIX2_SUPER_MAGIC;
- else
- magic = MINIX2_SUPER_MAGIC2;
- } else
+ 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 */
+ if (find_mount_point(G.device_name))
+ bb_error_msg_and_die("can't format mounted filesystem");
+
+ xmove_fd(xopen(G.device_name, O_RDWR), dev_fd);
+ if (fstat(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
- if (BLOCKS > 65535)
- BLOCKS = 65535;
- check_mount(); /* is it already mounted? */
- tmp = root_block;
+
+ tmp = G.root_block;
*(short *) tmp = 1;
strcpy(tmp + 2, ".");
- tmp += dirsize;
+ tmp += G.dirsize;
*(short *) tmp = 1;
strcpy(tmp + 2, "..");
- tmp += dirsize;
+ tmp += G.dirsize;
*(short *) tmp = 2;
strcpy(tmp + 2, ".badblocks");
- DEV = open(device_name, O_RDWR);
- if (DEV < 0)
- bb_error_msg_and_die("unable to open %s", device_name);
- if (fstat(DEV, &statbuf) < 0)
- bb_error_msg_and_die("unable to stat %s", device_name);
- if (!S_ISBLK(statbuf.st_mode))
- check = 0;
- else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
- bb_error_msg_and_die("will not try to make filesystem on '%s'", device_name);
+
setup_tables();
- if (check)
+
+ if (opt & 1) // -c ?
check_blocks();
else if (listfile)
get_list_blocks(listfile);
-#ifdef CONFIG_FEATURE_MINIX2
+
if (version2) {
make_root_inode2();
make_bad_inode2();
- } else
-#endif
- {
+ } else {
make_root_inode();
make_bad_inode();
}
+
mark_good_blocks();
write_tables();
- return( 0);
-
+ return 0;
}
diff --git a/release/src/router/busybox/util-linux/mkfs_vfat.c b/release/src/router/busybox/util-linux/mkfs_vfat.c
new file mode 100644
index 00000000..aa6ae92d
--- /dev/null
+++ b/release/src/router/busybox/util-linux/mkfs_vfat.c
@@ -0,0 +1,614 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mkfs_vfat: utility to create FAT32 filesystem
+ * inspired by dosfstools
+ *
+ * Busybox'ed (2009) by Vladimir Dronnikov <dronnikov@gmail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
+#include "volume_id/volume_id_internal.h"
+
+#include <linux/hdreg.h> /* HDIO_GETGEO */
+#include <linux/fd.h> /* FDGETPRM */
+//#include <linux/msdos_fs.h>
+
+#define SECTOR_SIZE 512
+
+#define SECTORS_PER_BLOCK (BLOCK_SIZE / SECTOR_SIZE)
+
+// M$ says the high 4 bits of a FAT32 FAT entry are reserved
+#define EOF_FAT32 0x0FFFFFF8
+#define BAD_FAT32 0x0FFFFFF7
+#define MAX_CLUST_32 0x0FFFFFF0
+
+#define ATTR_VOLUME 8
+
+#define NUM_FATS 2
+
+/* FAT32 filesystem looks like this:
+ * sector -nn...-1: "hidden" sectors, all sectors before this partition
+ * (-h hidden-sectors sets it. Useful only for boot loaders,
+ * they need to know _disk_ offset in order to be able to correctly
+ * address sectors relative to start of disk)
+ * sector 0: boot sector
+ * sector 1: info sector
+ * sector 2: set aside for boot code which didn't fit into sector 0
+ * ...(zero-filled sectors)...
+ * sector B: backup copy of sector 0 [B set by -b backup-boot-sector]
+ * sector B+1: backup copy of sector 1
+ * sector B+2: backup copy of sector 2
+ * ...(zero-filled sectors)...
+ * sector R: FAT#1 [R set by -R reserved-sectors]
+ * ...(FAT#1)...
+ * sector R+fat_size: FAT#2
+ * ...(FAT#2)...
+ * sector R+fat_size*2: cluster #2
+ * ...(cluster #2)...
+ * sector R+fat_size*2+clust_size: cluster #3
+ * ...(the rest is filled by clusters till the end)...
+ */
+
+enum {
+// Perhaps this should remain constant
+ info_sector_number = 1,
+// TODO: make these cmdline options
+// dont forget sanity check: backup_boot_sector + 3 <= reserved_sect
+ backup_boot_sector = 3,
+ reserved_sect = 6,
+};
+
+// how many blocks we try to read while testing
+#define TEST_BUFFER_BLOCKS 16
+
+struct msdos_dir_entry {
+ char name[11]; /* 000 name and extension */
+ uint8_t attr; /* 00b attribute bits */
+ uint8_t lcase; /* 00c case for base and extension */
+ uint8_t ctime_cs; /* 00d creation time, centiseconds (0-199) */
+ uint16_t ctime; /* 00e creation time */
+ uint16_t cdate; /* 010 creation date */
+ uint16_t adate; /* 012 last access date */
+ uint16_t starthi; /* 014 high 16 bits of cluster in FAT32 */
+ uint16_t time; /* 016 time */
+ uint16_t date; /* 018 date */
+ uint16_t start; /* 01a first cluster */
+ uint32_t size; /* 01c file size in bytes */
+} __attribute__ ((packed));
+
+/* Example of boot sector's beginning:
+0000 eb 58 90 4d 53 57 49 4e 34 2e 31 00 02 08 26 00 |...MSWIN4.1...&.|
+0010 02 00 00 00 00 f8 00 00 3f 00 ff 00 3f 00 00 00 |........?...?...|
+0020 54 9b d0 00 0d 34 00 00 00 00 00 00 02 00 00 00 |T....4..........|
+0030 01 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+0040 80 00 29 71 df 51 e0 4e 4f 20 4e 41 4d 45 20 20 |..)q.Q.NO NAME |
+0050 20 20 46 41 54 33 32 20 20 20 33 c9 8e d1 bc f4 | FAT32 3.....|
+*/
+struct msdos_volume_info { /* (offsets are relative to start of boot sector) */
+ uint8_t drive_number; /* 040 BIOS drive number */
+ uint8_t reserved; /* 041 unused */
+ uint8_t ext_boot_sign; /* 042 0x29 if fields below exist (DOS 3.3+) */
+ uint32_t volume_id32; /* 043 volume ID number */
+ char volume_label[11];/* 047 volume label */
+ char fs_type[8]; /* 052 typically "FATnn" */
+} __attribute__ ((packed)); /* 05a end. Total size 26 (0x1a) bytes */
+
+struct msdos_boot_sector {
+ char boot_jump[3]; /* 000 short or near jump instruction */
+ char system_id[8]; /* 003 name - can be used to special case partition manager volumes */
+ uint16_t bytes_per_sect; /* 00b bytes per logical sector */
+ uint8_t sect_per_clust; /* 00d sectors/cluster */
+ uint16_t reserved_sect; /* 00e reserved sectors (sector offset of 1st FAT relative to volume start) */
+ uint8_t fats; /* 010 number of FATs */
+ uint16_t dir_entries; /* 011 root directory entries */
+ uint16_t volume_size_sect; /* 013 volume size in sectors */
+ uint8_t media_byte; /* 015 media code */
+ uint16_t sect_per_fat; /* 016 sectors/FAT */
+ uint16_t sect_per_track; /* 018 sectors per track */
+ uint16_t heads; /* 01a number of heads */
+ uint32_t hidden; /* 01c hidden sectors (sector offset of volume within physical disk) */
+ uint32_t fat32_volume_size_sect; /* 020 volume size in sectors (if volume_size_sect == 0) */
+ uint32_t fat32_sect_per_fat; /* 024 sectors/FAT */
+ uint16_t fat32_flags; /* 028 bit 8: fat mirroring, low 4: active fat */
+ uint8_t fat32_version[2]; /* 02a major, minor filesystem version (I see 0,0) */
+ uint32_t fat32_root_cluster; /* 02c first cluster in root directory */
+ uint16_t fat32_info_sector; /* 030 filesystem info sector (usually 1) */
+ uint16_t fat32_backup_boot; /* 032 backup boot sector (usually 6) */
+ uint32_t reserved2[3]; /* 034 unused */
+ struct msdos_volume_info vi; /* 040 */
+ char boot_code[0x200 - 0x5a - 2]; /* 05a */
+#define BOOT_SIGN 0xAA55
+ uint16_t boot_sign; /* 1fe */
+} __attribute__ ((packed));
+
+#define FAT_FSINFO_SIG1 0x41615252
+#define FAT_FSINFO_SIG2 0x61417272
+struct fat32_fsinfo {
+ uint32_t signature1; /* 0x52,0x52,0x41,0x61, "RRaA" */
+ uint32_t reserved1[128 - 8];
+ uint32_t signature2; /* 0x72,0x72,0x61,0x41, "rrAa" */
+ uint32_t free_clusters; /* free cluster count. -1 if unknown */
+ uint32_t next_cluster; /* most recently allocated cluster */
+ uint32_t reserved2[3];
+ uint16_t reserved3; /* 1fc */
+ uint16_t boot_sign; /* 1fe */
+} __attribute__ ((packed));
+
+struct bug_check {
+ char BUG1[sizeof(struct msdos_dir_entry ) == 0x20 ? 1 : -1];
+ char BUG2[sizeof(struct msdos_volume_info) == 0x1a ? 1 : -1];
+ char BUG3[sizeof(struct msdos_boot_sector) == 0x200 ? 1 : -1];
+ char BUG4[sizeof(struct fat32_fsinfo ) == 0x200 ? 1 : -1];
+};
+
+static const char boot_code[] ALIGN1 =
+ "\x0e" /* 05a: push cs */
+ "\x1f" /* 05b: pop ds */
+ "\xbe\x77\x7c" /* write_msg: mov si, offset message_txt */
+ "\xac" /* 05f: lodsb */
+ "\x22\xc0" /* 060: and al, al */
+ "\x74\x0b" /* 062: jz key_press */
+ "\x56" /* 064: push si */
+ "\xb4\x0e" /* 065: mov ah, 0eh */
+ "\xbb\x07\x00" /* 067: mov bx, 0007h */
+ "\xcd\x10" /* 06a: int 10h */
+ "\x5e" /* 06c: pop si */
+ "\xeb\xf0" /* 06d: jmp write_msg */
+ "\x32\xe4" /* key_press: xor ah, ah */
+ "\xcd\x16" /* 071: int 16h */
+ "\xcd\x19" /* 073: int 19h */
+ "\xeb\xfe" /* foo: jmp foo */
+ /* 077: message_txt: */
+ "This is not a bootable disk\r\n";
+
+
+#define MARK_CLUSTER(cluster, value) \
+ ((uint32_t *)fat)[cluster] = cpu_to_le32(value)
+
+void BUG_unsupported_field_size(void);
+#define STORE_LE(field, value) \
+do { \
+ if (sizeof(field) == 4) \
+ field = cpu_to_le32(value); \
+ else if (sizeof(field) == 2) \
+ field = cpu_to_le16(value); \
+ else if (sizeof(field) == 1) \
+ field = (value); \
+ else \
+ BUG_unsupported_field_size(); \
+} while (0)
+
+/* compat:
+ * mkdosfs 2.11 (12 Mar 2005)
+ * Usage: mkdosfs [-A] [-c] [-C] [-v] [-I] [-l bad-block-file]
+ * [-b backup-boot-sector]
+ * [-m boot-msg-file] [-n volume-name] [-i volume-id]
+ * [-s sectors-per-cluster] [-S logical-sector-size]
+ * [-f number-of-FATs]
+ * [-h hidden-sectors] [-F fat-size] [-r root-dir-entries]
+ * [-R reserved-sectors]
+ * /dev/name [blocks]
+ */
+int mkfs_vfat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mkfs_vfat_main(int argc UNUSED_PARAM, char **argv)
+{
+ struct stat st;
+ const char *volume_label = "";
+ char *buf;
+ char *device_name;
+ uoff_t volume_size_bytes;
+ uoff_t volume_size_sect;
+ uint32_t total_clust;
+ uint32_t volume_id;
+ int dev;
+ unsigned bytes_per_sect;
+ unsigned sect_per_fat;
+ unsigned opts;
+ uint16_t sect_per_track;
+ uint8_t media_byte;
+ uint8_t sect_per_clust;
+ uint8_t heads;
+ enum {
+ OPT_A = 1 << 0, // [IGNORED] atari format
+ OPT_b = 1 << 1, // [IGNORED] location of backup boot sector
+ OPT_c = 1 << 2, // [IGNORED] check filesystem
+ OPT_C = 1 << 3, // [IGNORED] create a new file
+ OPT_f = 1 << 4, // [IGNORED] number of FATs
+ OPT_F = 1 << 5, // [IGNORED, implied 32] choose FAT size
+ OPT_h = 1 << 6, // [IGNORED] number of hidden sectors
+ OPT_I = 1 << 7, // [IGNORED] don't bark at entire disk devices
+ OPT_i = 1 << 8, // [IGNORED] volume ID
+ OPT_l = 1 << 9, // [IGNORED] bad block filename
+ OPT_m = 1 << 10, // [IGNORED] message file
+ OPT_n = 1 << 11, // volume label
+ OPT_r = 1 << 12, // [IGNORED] root directory entries
+ OPT_R = 1 << 13, // [IGNORED] number of reserved sectors
+ OPT_s = 1 << 14, // [IGNORED] sectors per cluster
+ OPT_S = 1 << 15, // [IGNORED] sector size
+ OPT_v = 1 << 16, // verbose
+ };
+
+ opt_complementary = "-1";//:b+:f+:F+:h+:r+:R+:s+:S+:vv:c--l:l--c";
+ opts = getopt32(argv, "Ab:cCf:F:h:Ii:l:m:n:r:R:s:S:v",
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, &volume_label, NULL, NULL, NULL, NULL);
+ argv += optind;
+
+ // cache device name
+ device_name = argv[0];
+ // default volume ID = creation time
+ volume_id = time(NULL);
+
+ dev = xopen(device_name, O_EXCL | O_RDWR);
+ if (fstat(dev, &st) < 0)
+ bb_simple_perror_msg_and_die(device_name);
+
+ //
+ // Get image size and sector size
+ //
+ bytes_per_sect = SECTOR_SIZE;
+ volume_size_bytes = st.st_size;
+ if (!S_ISBLK(st.st_mode)) {
+ if (!S_ISREG(st.st_mode)) {
+ if (!argv[1])
+ bb_error_msg_and_die("image size must be specified");
+ }
+ // not a block device, skip bad sectors check
+ opts &= ~OPT_c;
+ } else {
+ int min_bytes_per_sect;
+
+ // more portable than BLKGETSIZE[64]
+ volume_size_bytes = xlseek(dev, 0, SEEK_END);
+ xlseek(dev, 0, SEEK_SET);
+#if 0
+ unsigned device_num;
+ // for true block devices we do check sanity
+ device_num = st.st_rdev & 0xff3f;
+ // do we allow to format the whole disk device?
+ if (!(opts & OPT_I) && (
+ device_num == 0x0300 || // hda, hdb
+ (device_num & 0xff0f) == 0x0800 || // sd
+ device_num == 0x0d00 || // xd
+ device_num == 0x1600 ) // hdc, hdd
+ )
+ bb_error_msg_and_die("will not try to make filesystem on full-disk device (use -I if wanted)");
+ // can't work on mounted filesystems
+ if (find_mount_point(device_name))
+ bb_error_msg_and_die("can't format mounted filesystem");
+#endif
+ // get true sector size
+ // (parameter must be int*, not long* or size_t*)
+ xioctl(dev, BLKSSZGET, &min_bytes_per_sect);
+ if (min_bytes_per_sect > SECTOR_SIZE) {
+ bytes_per_sect = min_bytes_per_sect;
+ bb_error_msg("for this device sector size is %u", min_bytes_per_sect);
+ }
+ }
+ if (argv[1]) {
+ volume_size_bytes = XATOOFF(argv[1]);
+ if (volume_size_bytes >= MAXINT(off_t) / 1024)
+ bb_error_msg_and_die("image size is too big");
+ volume_size_bytes *= 1024;
+ }
+ volume_size_sect = volume_size_bytes / bytes_per_sect;
+
+ //
+ // Find out or guess media parameters
+ //
+ media_byte = 0xf8;
+ heads = 255;
+ sect_per_track = 63;
+ sect_per_clust = 1;
+ {
+ struct hd_geometry geometry;
+ // size (in sectors), sect (per track), head
+ struct floppy_struct param;
+
+ // N.B. whether to use HDIO_GETGEO or HDIO_REQ?
+ if (ioctl(dev, HDIO_GETGEO, &geometry) == 0
+ && geometry.sectors
+ && geometry.heads
+ ) {
+ // hard drive
+ sect_per_track = geometry.sectors;
+ heads = geometry.heads;
+
+ set_cluster_size:
+ /* For FAT32, try to do the same as M$'s format command
+ * (see http://www.win.tue.nl/~aeb/linux/fs/fat/fatgen103.pdf p. 20):
+ * fs size <= 260M: 0.5k clusters
+ * fs size <= 8G: 4k clusters
+ * fs size <= 16G: 8k clusters
+ * fs size > 16G: 16k clusters
+ */
+ sect_per_clust = 1;
+ if (volume_size_bytes >= 260*1024*1024) {
+ sect_per_clust = 8;
+ /* fight gcc: */
+ /* "error: integer overflow in expression" */
+ /* "error: right shift count >= width of type" */
+ if (sizeof(off_t) > 4) {
+ unsigned t = (volume_size_bytes >> 31 >> 1);
+ if (t >= 8/4)
+ sect_per_clust = 16;
+ if (t >= 16/4)
+ sect_per_clust = 32;
+ }
+ }
+ } else {
+ // floppy, loop, or regular file
+ int not_floppy = ioctl(dev, FDGETPRM, &param);
+ if (not_floppy == 0) {
+ // floppy disk
+ sect_per_track = param.sect;
+ heads = param.head;
+ volume_size_sect = param.size;
+ volume_size_bytes = param.size * SECTOR_SIZE;
+ }
+ // setup the media descriptor byte
+ switch (volume_size_sect) {
+ case 2*360: // 5.25", 2, 9, 40 - 360K
+ media_byte = 0xfd;
+ break;
+ case 2*720: // 3.5", 2, 9, 80 - 720K
+ case 2*1200: // 5.25", 2, 15, 80 - 1200K
+ media_byte = 0xf9;
+ break;
+ default: // anything else
+ if (not_floppy)
+ goto set_cluster_size;
+ case 2*1440: // 3.5", 2, 18, 80 - 1440K
+ case 2*2880: // 3.5", 2, 36, 80 - 2880K
+ media_byte = 0xf0;
+ break;
+ }
+ // not floppy, but size matches floppy exactly.
+ // perhaps it is a floppy image.
+ // we already set media_byte as if it is a floppy,
+ // now set sect_per_track and heads.
+ heads = 2;
+ sect_per_track = (unsigned)volume_size_sect / 160;
+ if (sect_per_track < 9)
+ sect_per_track = 9;
+ }
+ }
+
+ //
+ // Calculate number of clusters, sectors/cluster, sectors/FAT
+ // (an initial guess for sect_per_clust should already be set)
+ //
+ // "mkdosfs -v -F 32 image5k 5" is the minimum:
+ // 2 sectors for FATs and 2 data sectors
+ if ((off_t)(volume_size_sect - reserved_sect) < 4)
+ bb_error_msg_and_die("the image is too small for FAT32");
+ sect_per_fat = 1;
+ while (1) {
+ while (1) {
+ int spf_adj;
+ off_t tcl = (volume_size_sect - reserved_sect - NUM_FATS * sect_per_fat) / sect_per_clust;
+ // tcl may be > MAX_CLUST_32 here, but it may be
+ // because sect_per_fat is underestimated,
+ // and with increased sect_per_fat it still may become
+ // <= MAX_CLUST_32. Therefore, we do not check
+ // against MAX_CLUST_32, but against a bigger const:
+ if (tcl > 0x7fffffff)
+ goto next;
+ total_clust = tcl; // fits in uint32_t
+ spf_adj = ((total_clust + 2) * 4 + bytes_per_sect - 1) / bytes_per_sect - sect_per_fat;
+#if 0
+ bb_error_msg("sect_per_clust:%u sect_per_fat:%u total_clust:%u",
+ sect_per_clust, sect_per_fat, (int)tcl);
+ bb_error_msg("adjust to sect_per_fat:%d", spf_adj);
+#endif
+ if (spf_adj <= 0) {
+ // do not need to adjust sect_per_fat.
+ // so, was total_clust too big after all?
+ if (total_clust <= MAX_CLUST_32)
+ goto found_total_clust; // no
+ // yes, total_clust is _a bit_ too big
+ goto next;
+ }
+ // adjust sect_per_fat, go back and recalc total_clust
+ // (note: just "sect_per_fat += spf_adj" isn't ok)
+ sect_per_fat += ((unsigned)spf_adj / 2) | 1;
+ }
+ next:
+ if (sect_per_clust == 128)
+ bb_error_msg_and_die("can't make FAT32 with >128 sectors/cluster");
+ sect_per_clust *= 2;
+ sect_per_fat = (sect_per_fat / 2) | 1;
+ }
+ found_total_clust:
+
+ //
+ // Print info
+ //
+ if (opts & OPT_v) {
+ fprintf(stderr,
+ "Device '%s':\n"
+ "heads:%u, sectors/track:%u, bytes/sector:%u\n"
+ "media descriptor:%02x\n"
+ "total sectors:%"OFF_FMT"u, clusters:%u, sectors/cluster:%u\n"
+ "FATs:2, sectors/FAT:%u\n"
+ "volumeID:%08x, label:'%s'\n",
+ device_name,
+ heads, sect_per_track, bytes_per_sect,
+ (int)media_byte,
+ volume_size_sect, (int)total_clust, (int)sect_per_clust,
+ sect_per_fat,
+ (int)volume_id, volume_label
+ );
+ }
+
+ //
+ // Write filesystem image sequentially (no seeking)
+ //
+ {
+ // (a | b) is poor man's max(a, b)
+ unsigned bufsize = reserved_sect;
+ //bufsize |= sect_per_fat; // can be quite large
+ bufsize |= 2; // use this instead
+ bufsize |= sect_per_clust;
+ buf = xzalloc(bufsize * bytes_per_sect);
+ }
+
+ { // boot and fsinfo sectors, and their copies
+ struct msdos_boot_sector *boot_blk = (void*)buf;
+ struct fat32_fsinfo *info = (void*)(buf + bytes_per_sect);
+
+ strcpy(boot_blk->boot_jump, "\xeb\x58\x90" "mkdosfs"); // system_id[8] included :)
+ STORE_LE(boot_blk->bytes_per_sect, bytes_per_sect);
+ STORE_LE(boot_blk->sect_per_clust, sect_per_clust);
+ STORE_LE(boot_blk->reserved_sect, reserved_sect);
+ STORE_LE(boot_blk->fats, 2);
+ //STORE_LE(boot_blk->dir_entries, 0); // for FAT32, stays 0
+ if (volume_size_sect <= 0xffff)
+ STORE_LE(boot_blk->volume_size_sect, volume_size_sect);
+ STORE_LE(boot_blk->media_byte, media_byte);
+ // wrong: this would make Linux think that it's fat12/16:
+ //if (sect_per_fat <= 0xffff)
+ // STORE_LE(boot_blk->sect_per_fat, sect_per_fat);
+ // works:
+ //STORE_LE(boot_blk->sect_per_fat, 0);
+ STORE_LE(boot_blk->sect_per_track, sect_per_track);
+ STORE_LE(boot_blk->heads, heads);
+ //STORE_LE(boot_blk->hidden, 0);
+ STORE_LE(boot_blk->fat32_volume_size_sect, volume_size_sect);
+ STORE_LE(boot_blk->fat32_sect_per_fat, sect_per_fat);
+ //STORE_LE(boot_blk->fat32_flags, 0);
+ //STORE_LE(boot_blk->fat32_version[2], 0,0);
+ STORE_LE(boot_blk->fat32_root_cluster, 2);
+ STORE_LE(boot_blk->fat32_info_sector, info_sector_number);
+ STORE_LE(boot_blk->fat32_backup_boot, backup_boot_sector);
+ //STORE_LE(boot_blk->reserved2[3], 0,0,0);
+ STORE_LE(boot_blk->vi.ext_boot_sign, 0x29);
+ STORE_LE(boot_blk->vi.volume_id32, volume_id);
+ strncpy(boot_blk->vi.fs_type, "FAT32 ", sizeof(boot_blk->vi.fs_type));
+ strncpy(boot_blk->vi.volume_label, volume_label, sizeof(boot_blk->vi.volume_label));
+ memcpy(boot_blk->boot_code, boot_code, sizeof(boot_code));
+ STORE_LE(boot_blk->boot_sign, BOOT_SIGN);
+
+ STORE_LE(info->signature1, FAT_FSINFO_SIG1);
+ STORE_LE(info->signature2, FAT_FSINFO_SIG2);
+ // we've allocated cluster 2 for the root dir
+ STORE_LE(info->free_clusters, (total_clust - 1));
+ STORE_LE(info->next_cluster, 2);
+ STORE_LE(info->boot_sign, BOOT_SIGN);
+
+ // 1st copy
+ xwrite(dev, buf, bytes_per_sect * backup_boot_sector);
+ // 2nd copy and possibly zero sectors
+ xwrite(dev, buf, bytes_per_sect * (reserved_sect - backup_boot_sector));
+ }
+
+ { // file allocation tables
+ unsigned i,j;
+ unsigned char *fat = (void*)buf;
+
+ memset(buf, 0, bytes_per_sect * 2);
+ // initial FAT entries
+ MARK_CLUSTER(0, 0x0fffff00 | media_byte);
+ MARK_CLUSTER(1, 0xffffffff);
+ // mark cluster 2 as EOF (used for root dir)
+ MARK_CLUSTER(2, EOF_FAT32);
+ for (i = 0; i < NUM_FATS; i++) {
+ xwrite(dev, buf, bytes_per_sect);
+ for (j = 1; j < sect_per_fat; j++)
+ xwrite(dev, buf + bytes_per_sect, bytes_per_sect);
+ }
+ }
+
+ // root directory
+ // empty directory is just a set of zero bytes
+ memset(buf, 0, sect_per_clust * bytes_per_sect);
+ if (volume_label[0]) {
+ // create dir entry for volume_label
+ struct msdos_dir_entry *de;
+#if 0
+ struct tm tm;
+ uint16_t t, d;
+#endif
+ de = (void*)buf;
+ strncpy(de->name, volume_label, sizeof(de->name));
+ STORE_LE(de->attr, ATTR_VOLUME);
+#if 0
+ localtime_r(&create_time, &tm);
+ t = (tm.tm_sec >> 1) + (tm.tm_min << 5) + (tm.tm_hour << 11);
+ d = tm.tm_mday + ((tm.tm_mon+1) << 5) + ((tm.tm_year-80) << 9);
+ STORE_LE(de->time, t);
+ STORE_LE(de->date, d);
+ //STORE_LE(de->ctime_cs, 0);
+ de->ctime = de->time;
+ de->cdate = de->date;
+ de->adate = de->date;
+#endif
+ }
+ xwrite(dev, buf, sect_per_clust * bytes_per_sect);
+
+#if 0
+ if (opts & OPT_c) {
+ uoff_t volume_size_blocks;
+ unsigned start_data_sector;
+ unsigned start_data_block;
+ unsigned badblocks = 0;
+ int try, got;
+ off_t currently_testing;
+ char *blkbuf = xmalloc(BLOCK_SIZE * TEST_BUFFER_BLOCKS);
+
+ volume_size_blocks = (volume_size_bytes >> BLOCK_SIZE_BITS);
+ // N.B. the two following vars are in hard sectors, i.e. SECTOR_SIZE byte sectors!
+ start_data_sector = (reserved_sect + NUM_FATS * sect_per_fat) * (bytes_per_sect / SECTOR_SIZE);
+ start_data_block = (start_data_sector + SECTORS_PER_BLOCK - 1) / SECTORS_PER_BLOCK;
+
+ bb_info_msg("Searching for bad blocks ");
+ currently_testing = 0;
+ try = TEST_BUFFER_BLOCKS;
+ while (currently_testing < volume_size_blocks) {
+ if (currently_testing + try > volume_size_blocks)
+ try = volume_size_blocks - currently_testing;
+ // perform a test on a block. return the number of blocks
+ // that could be read successfully.
+ // seek to the correct location
+ xlseek(dev, currently_testing * BLOCK_SIZE, SEEK_SET);
+ // try reading
+ got = read(dev, blkbuf, try * BLOCK_SIZE);
+ if (got < 0)
+ got = 0;
+ if (got & (BLOCK_SIZE - 1))
+ bb_error_msg("Unexpected values in do_check: probably bugs");
+ got /= BLOCK_SIZE;
+ currently_testing += got;
+ if (got == try) {
+ try = TEST_BUFFER_BLOCKS;
+ continue;
+ }
+ try = 1;
+ if (currently_testing < start_data_block)
+ bb_error_msg_and_die("bad blocks before data-area: cannot make fs");
+
+ // mark all of the sectors in the block as bad
+ for (i = 0; i < SECTORS_PER_BLOCK; i++) {
+ int cluster = (currently_testing * SECTORS_PER_BLOCK + i - start_data_sector) / (int) (sect_per_clust) / (bytes_per_sect / SECTOR_SIZE);
+ if (cluster < 0)
+ bb_error_msg_and_die("Invalid cluster number in mark_sector: probably bug!");
+ MARK_CLUSTER(cluster, BAD_FAT32);
+ }
+ badblocks++;
+ currently_testing++;
+ }
+ free(blkbuf);
+ if (badblocks)
+ bb_info_msg("%d bad block(s)", badblocks);
+ }
+#endif
+
+ // cleanup
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(buf);
+ close(dev);
+ }
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/mkswap.c b/release/src/router/busybox/util-linux/mkswap.c
index 30a364ce..11c411b6 100644
--- a/release/src/router/busybox/util-linux/mkswap.c
+++ b/release/src/router/busybox/util-linux/mkswap.c
@@ -1,422 +1,129 @@
/* vi: set sw=4 ts=4: */
-/*
- * mkswap.c - set up a linux swap device
- *
- * (C) 1991 Linus Torvalds. This file may be redistributed as per
- * the Linux copyright.
- */
-
-/*
- * 20.12.91 - time began. Got VM working yesterday by doing this by hand.
- *
- * Usage: mkswap [-c] [-vN] [-f] device [size-in-blocks]
- *
- * -c for readability checking. (Use it unless you are SURE!)
- * -vN for swap areas version N. (Only N=0,1 known today.)
- * -f for forcing swap creation even if it would smash partition table.
- *
- * The device may be a block device or an image of one, but this isn't
- * enforced (but it's not much fun on a character device :-).
- *
- * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the
- * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995.
- *
- * Version 1 swap area code (for kernel 2.1.117), aeb, 981010.
- *
- * Sparc fixes, jj@ultra.linux.cz (Jakub Jelinek), 981201 - mangled by aeb.
- * V1_MAX_PAGES fixes, jj, 990325.
- *
- * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
- * - added Native Language Support
+/* mkswap.c - format swap device (Linux v1 only)
*
- * from util-linux -- adapted for busybox by
- * Erik Andersen <andersen@codepoet.org>. I ripped out Native Language
- * Support, made some stuff smaller, and fitted for life in busybox.
+ * Copyright 2006 Rob Landley <rob@landley.net>
*
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/ioctl.h> /* for _IO */
-#include <sys/utsname.h>
-#include <asm/page.h> /* for PAGE_SIZE and PAGE_SHIFT */
- /* we also get PAGE_SIZE via getpagesize() */
-#include "busybox.h"
-
-#ifndef _IO
-/* pre-1.3.45 */
-static const int BLKGETSIZE = 0x1260;
-#else
-/* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */
-#define BLKGETSIZE _IO(0x12,96)
-#endif
-
-static char *device_name = NULL;
-static int DEV = -1;
-static long PAGES = 0;
-static int check = 0;
-static int badpages = 0;
-static int version = -1;
-
-#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
-
-/*
- * The definition of the union swap_header uses the constant PAGE_SIZE.
- * Unfortunately, on some architectures this depends on the hardware model,
- * and can only be found at run time -- we use getpagesize().
- */
-
-static int pagesize;
-static int *signature_page;
-
-static struct swap_header_v1 {
- char bootbits[1024]; /* Space for disklabel etc. */
- unsigned int version;
- unsigned int last_page;
- unsigned int nr_badpages;
- unsigned int padding[125];
- unsigned int badpages[1];
-} *p;
-
-static inline void init_signature_page(void)
-{
- pagesize = getpagesize();
-
-#ifdef PAGE_SIZE
- if (pagesize != PAGE_SIZE)
- bb_error_msg("Assuming pages of size %d", pagesize);
-#endif
- signature_page = (int *) xmalloc(pagesize);
- memset(signature_page, 0, pagesize);
- p = (struct swap_header_v1 *) signature_page;
-}
-
-static inline void write_signature(char *sig)
-{
- char *sp = (char *) signature_page;
-
- strncpy(sp + pagesize - 10, sig, 10);
-}
-
-#define V0_MAX_PAGES (8 * (pagesize - 10))
-/* Before 2.2.0pre9 */
-#define V1_OLD_MAX_PAGES ((0x7fffffff / pagesize) - 1)
-/* Since 2.2.0pre9:
- error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL))
- with variations on
- #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
- #define SWP_OFFSET(entry) ((entry) >> 8)
- on the various architectures. Below the result - yuk.
-
- Machine pagesize SWP_ENTRY SWP_OFFSET bound+1 oldbound+2
- i386 2^12 o<<8 e>>8 1<<24 1<<19
- mips 2^12 o<<15 e>>15 1<<17 1<<19
- alpha 2^13 o<<40 e>>40 1<<24 1<<18
- m68k 2^12 o<<12 e>>12 1<<20 1<<19
- sparc 2^{12,13} (o&0x3ffff)<<9 (e>>9)&0x3ffff 1<<18 1<<{19,18}
- sparc64 2^13 o<<13 e>>13 1<<51 1<<18
- ppc 2^12 o<<8 e>>8 1<<24 1<<19
- armo 2^{13,14,15} o<<8 e>>8 1<<24 1<<{18,17,16}
- armv 2^12 o<<9 e>>9 1<<23 1<<19
-
- assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere.
-
- The bad part is that we need to know this since the kernel will
- refuse a swap space if it is too large.
-*/
-/* patch from jj - why does this differ from the above? */
-#if defined(__alpha__)
-#define V1_MAX_PAGES ((1 << 24) - 1)
-#elif defined(__mips__)
-#define V1_MAX_PAGES ((1 << 17) - 1)
-#elif defined(__sparc_v9__)
-#define V1_MAX_PAGES ((3 << 29) - 1)
-#elif defined(__sparc__)
-#define V1_MAX_PAGES (pagesize == 8192 ? ((3 << 29) - 1) : ((1 << 18) - 1))
-#else
-#define V1_MAX_PAGES V1_OLD_MAX_PAGES
-#endif
-/* man page now says:
-The maximum useful size of a swap area now depends on the architecture.
-It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips,
-128GB on alpha and 3TB on sparc64.
-*/
-
-#define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int))
-
-static inline void bit_set(unsigned int *addr, unsigned int nr)
-{
- unsigned int r, m;
-
- addr += nr / (8 * sizeof(int));
-
- r = *addr;
- m = 1 << (nr & (8 * sizeof(int) - 1));
-
- *addr = r | m;
-}
-
-static int bit_test_and_clear(unsigned int *addr, unsigned int nr)
-{
- unsigned int r, m;
-
- addr += nr / (8 * sizeof(int));
-
- r = *addr;
- m = 1 << (nr & (8 * sizeof(int) - 1));
-
- *addr = r & ~m;
- return (r & m) != 0;
-}
-
-
-static void page_ok(int page)
-{
- if (version == 0)
- bit_set(signature_page, page);
-}
-
-static inline void page_bad(int page)
-{
- if (version == 0)
- bit_test_and_clear(signature_page, page);
- else {
- if (badpages == MAX_BADPAGES)
- bb_error_msg_and_die("too many bad pages");
- p->badpages[badpages] = page;
- }
- badpages++;
-}
+#include "libbb.h"
-static void check_blocks(void)
+#if ENABLE_SELINUX
+static void mkswap_selinux_setcontext(int fd, const char *path)
{
- unsigned int current_page;
- int do_seek = 1;
- char *buffer;
-
- buffer = xmalloc(pagesize);
- current_page = 0;
- while (current_page < PAGES) {
- if (!check) {
- page_ok(current_page++);
- continue;
+ struct stat stbuf;
+
+ if (!is_selinux_enabled())
+ return;
+
+ if (fstat(fd, &stbuf) < 0)
+ bb_perror_msg_and_die("fstat failed");
+ if (S_ISREG(stbuf.st_mode)) {
+ security_context_t newcon;
+ security_context_t oldcon = NULL;
+ context_t context;
+
+ if (fgetfilecon(fd, &oldcon) < 0) {
+ if (errno != ENODATA)
+ goto error;
+ if (matchpathcon(path, stbuf.st_mode, &oldcon) < 0)
+ goto error;
}
- if (do_seek && lseek(DEV, current_page * pagesize, SEEK_SET) !=
- current_page * pagesize)
- bb_error_msg_and_die("seek failed in check_blocks");
- if ((do_seek = (pagesize != read(DEV, buffer, pagesize)))) {
- page_bad(current_page++);
- continue;
+ context = context_new(oldcon);
+ if (!context || context_type_set(context, "swapfile_t"))
+ goto error;
+ newcon = context_str(context);
+ if (!newcon)
+ goto error;
+ /* fsetfilecon_raw is hidden */
+ if (strcmp(oldcon, newcon) != 0 && fsetfilecon(fd, newcon) < 0)
+ goto error;
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ context_free(context);
+ freecon(oldcon);
}
- page_ok(current_page++);
}
- if (badpages == 1)
- printf("one bad page\n");
- else if (badpages > 1)
- printf("%d bad pages\n", badpages);
-}
-
-static long valid_offset(int fd, int offset)
-{
- char ch;
-
- if (lseek(fd, offset, 0) < 0)
- return 0;
- if (read(fd, &ch, 1) < 1)
- return 0;
- return 1;
+ return;
+ error:
+ bb_perror_msg_and_die("SELinux relabeling failed");
}
+#else
+#define mkswap_selinux_setcontext(fd, path) ((void)0)
+#endif
-static int find_size(int fd)
-{
- unsigned int high, low;
-
- low = 0;
- for (high = 1; high > 0 && 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;
- }
- return (low + 1);
-}
+#if 0 /* from Linux 2.6.23 */
+/*
+ * Magic header for a swap area. The first part of the union is
+ * what the swap magic looks like for the old (limited to 128MB)
+ * swap area format, the second part of the union adds - in the
+ * old reserved area - some extra information. Note that the first
+ * kilobyte is reserved for boot loader or disk label stuff...
+ */
+union swap_header {
+ struct {
+ char reserved[PAGE_SIZE - 10];
+ char magic[10]; /* SWAP-SPACE or SWAPSPACE2 */
+ } magic;
+ struct {
+ char bootbits[1024]; /* Space for disklabel etc. */
+ __u32 version; /* second kbyte, word 0 */
+ __u32 last_page; /* 1 */
+ __u32 nr_badpages; /* 2 */
+ unsigned char sws_uuid[16]; /* 3,4,5,6 */
+ unsigned char sws_volume[16]; /* 7,8,9,10 */
+ __u32 padding[117]; /* 11..127 */
+ __u32 badpages[1]; /* 128, total 129 32-bit words */
+ } info;
+};
+#endif
-/* return size in pages, to avoid integer overflow */
-static long get_size(const char *file)
-{
- int fd;
- long size;
+#define NWORDS 129
+#define hdr ((uint32_t*)(&bb_common_bufsiz1))
- if ((fd = open(file, O_RDONLY)) < 0)
- bb_perror_msg_and_die("%s", file);
- if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
- int sectors_per_page = pagesize / 512;
+struct BUG_bufsiz1_is_too_small {
+ char BUG_bufsiz1_is_too_small[COMMON_BUFSIZE < (NWORDS * 4) ? -1 : 1];
+};
- size /= sectors_per_page;
- } else {
- size = find_size(fd) / pagesize;
- }
- close(fd);
- return size;
-}
+/* Stored without terminating NUL */
+static const char SWAPSPACE2[sizeof("SWAPSPACE2")-1] ALIGN1 = "SWAPSPACE2";
+int mkswap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int mkswap_main(int argc, char **argv)
{
- char *tmp;
- struct stat statbuf;
- int sz;
- int maxpages;
- int goodpages;
- int offset;
- int force = 0;
+ int fd, pagesize;
+ off_t len;
- init_signature_page(); /* get pagesize */
+ // No options supported.
- while (argc-- > 1) {
- argv++;
- if (argv[0][0] != '-') {
- if (device_name) {
- int blocks_per_page = pagesize / 1024;
+ if (argc != 2) bb_show_usage();
- PAGES = strtol(argv[0], &tmp, 0) / blocks_per_page;
- if (*tmp)
- bb_show_usage();
- } else
- device_name = argv[0];
- } else {
- switch (argv[0][1]) {
- case 'c':
- check = 1;
- break;
- case 'f':
- force = 1;
- break;
- case 'v':
- version = atoi(argv[0] + 2);
- break;
- default:
- bb_show_usage();
- }
- }
- }
- if (!device_name) {
- bb_error_msg("error: Nowhere to set up swap on?");
- bb_show_usage();
- }
- sz = get_size(device_name);
- if (!PAGES) {
- PAGES = sz;
- } else if (PAGES > sz && !force) {
- bb_error_msg("error: size %ld is larger than device size %d",
- PAGES * (pagesize / 1024), sz * (pagesize / 1024));
- return EXIT_FAILURE;
- }
+ // Figure out how big the device is and announce our intentions.
- if (version == -1) {
- if (PAGES <= V0_MAX_PAGES)
- version = 0;
- else if (get_kernel_revision() < MAKE_VERSION(2, 1, 117))
- version = 0;
- else if (pagesize < 2048)
- version = 0;
- else
- version = 1;
- }
- if (version != 0 && version != 1) {
- bb_error_msg("error: unknown version %d", version);
- bb_show_usage();
- }
- if (PAGES < 10) {
- bb_error_msg("error: swap area needs to be at least %ldkB",
- (long) (10 * pagesize / 1024));
- bb_show_usage();
- }
-#if 0
- maxpages = ((version == 0) ? V0_MAX_PAGES : V1_MAX_PAGES);
-#else
- if (!version)
- maxpages = V0_MAX_PAGES;
- else if (get_kernel_revision() >= MAKE_VERSION(2, 2, 1))
- maxpages = V1_MAX_PAGES;
- else {
- maxpages = V1_OLD_MAX_PAGES;
- if (maxpages > V1_MAX_PAGES)
- maxpages = V1_MAX_PAGES;
- }
+ fd = xopen(argv[1], O_RDWR);
+ /* fdlength was reported to be unreliable - use seek */
+ len = xlseek(fd, 0, SEEK_END);
+#if ENABLE_SELINUX
+ xlseek(fd, 0, SEEK_SET);
#endif
- if (PAGES > maxpages) {
- PAGES = maxpages;
- bb_error_msg("warning: truncating swap area to %ldkB",
- PAGES * pagesize / 1024);
- }
-
- DEV = open(device_name, O_RDWR);
- if (DEV < 0 || fstat(DEV, &statbuf) < 0)
- bb_perror_msg_and_die("%s", device_name);
- if (!S_ISBLK(statbuf.st_mode))
- check = 0;
- else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
- bb_error_msg_and_die("Will not try to make swapdevice on '%s'", device_name);
-
-#ifdef __sparc__
- if (!force && version == 0) {
- /* Don't overwrite partition table unless forced */
- unsigned char *buffer = (unsigned char *) signature_page;
- unsigned short *q, sum;
+ pagesize = getpagesize();
+ printf("Setting up swapspace version 1, size = %"OFF_FMT"u bytes\n",
+ len - pagesize);
+ mkswap_selinux_setcontext(fd, argv[1]);
- if (read(DEV, buffer, 512) != 512)
- bb_error_msg_and_die("fatal: first page unreadable");
- if (buffer[508] == 0xDA && buffer[509] == 0xBE) {
- q = (unsigned short *) (buffer + 510);
- for (sum = 0; q >= (unsigned short *) buffer;)
- sum ^= *q--;
- if (!sum) {
- bb_error_msg("Device '%s' contains a valid Sun disklabel.\n"
-"This probably means creating v0 swap would destroy your partition table\n"
-"No swap created. If you really want to create swap v0 on that device, use\n"
-"the -f option to force it.", device_name);
- return EXIT_FAILURE;
- }
- }
- }
-#endif
+ // Make a header. hdr is zero-filled so far...
+ hdr[0] = 1;
+ hdr[1] = (len / pagesize) - 1;
- if (version == 0 || check)
- check_blocks();
- if (version == 0 && !bit_test_and_clear(signature_page, 0))
- bb_error_msg_and_die("fatal: first page unreadable");
- if (version == 1) {
- p->version = version;
- p->last_page = PAGES - 1;
- p->nr_badpages = badpages;
- }
+ // Write the header. Sync to disk because some kernel versions check
+ // signature on disk (not in cache) during swapon.
- goodpages = PAGES - badpages - 1;
- if (goodpages <= 0)
- bb_error_msg_and_die("Unable to set up swap-space: unreadable");
- printf("Setting up swapspace version %d, size = %ld bytes\n",
- version, (long) (goodpages * pagesize));
- write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2");
+ xlseek(fd, 1024, SEEK_SET);
+ xwrite(fd, hdr, NWORDS * 4);
+ xlseek(fd, pagesize - 10, SEEK_SET);
+ xwrite(fd, SWAPSPACE2, 10);
+ fsync(fd);
- offset = ((version == 0) ? 0 : 1024);
- if (lseek(DEV, offset, SEEK_SET) != offset)
- bb_error_msg_and_die("unable to rewind swap-device");
- if (write(DEV, (char *) signature_page + offset, pagesize - offset)
- != pagesize - offset)
- bb_error_msg_and_die("unable to write signature page");
+ if (ENABLE_FEATURE_CLEAN_UP) close(fd);
- /*
- * A subsequent swapon() will fail if the signature
- * is not actually on disk. (This is a kernel bug.)
- */
- if (fsync(DEV))
- bb_error_msg_and_die("fsync failed");
- return EXIT_SUCCESS;
+ return 0;
}
diff --git a/release/src/router/busybox/util-linux/more.c b/release/src/router/busybox/util-linux/more.c
index 1ec3007b..b0f20c44 100644
--- a/release/src/router/busybox/util-linux/more.c
+++ b/release/src/router/busybox/util-linux/more.c
@@ -3,216 +3,199 @@
* Mini more implementation for busybox
*
* Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
+ * 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
+ * based on the original more implementation by Bruce, and code from the
* Debian boot-floppies team.
*
* Termios corrects by Vladimir Oleynik <dzo@simtreas.ru>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file License in this tarball for details.
*/
-#include <stdio.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-
-static FILE *cin;
+#include "libbb.h"
-#ifdef CONFIG_FEATURE_USE_TERMIOS
-#include <termios.h>
-#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)
-#define getTermSettings(fd,argp) tcgetattr(fd, argp);
+#if ENABLE_FEATURE_USE_TERMIOS
-static struct termios initial_settings, new_settings;
+struct globals {
+ int cin_fileno;
+ struct termios initial_settings;
+ struct termios new_settings;
+};
+#define G (*(struct globals*)bb_common_bufsiz1)
+#define INIT_G() ((void)0)
+#define initial_settings (G.initial_settings)
+#define new_settings (G.new_settings )
+#define cin_fileno (G.cin_fileno )
-static void set_tty_to_initial_mode(void)
-{
- setTermSettings(fileno(cin), &initial_settings);
-}
+#define setTermSettings(fd, argp) tcsetattr(fd, TCSANOW, argp)
+#define getTermSettings(fd, argp) tcgetattr(fd, argp)
-static void gotsig(int sig)
+static void gotsig(int sig UNUSED_PARAM)
{
- putchar('\n');
+ bb_putchar('\n');
+ setTermSettings(cin_fileno, &initial_settings);
exit(EXIT_FAILURE);
}
-#endif /* CONFIG_FEATURE_USE_TERMIOS */
+#else /* !FEATURE_USE_TERMIOS */
+#define INIT_G() ((void)0)
+#define setTermSettings(fd, argp) ((void)0)
+#endif /* FEATURE_USE_TERMIOS */
-static int terminal_width = 79; /* not 80 in case terminal has linefold bug */
-static int terminal_height = 24;
+#define CONVERTED_TAB_SIZE 8
-
-extern int more_main(int argc, char **argv)
+int more_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int more_main(int argc UNUSED_PARAM, char **argv)
{
- int c, lines, input = 0;
- int please_display_more_prompt = -1;
+ int c = c; /* for gcc */
+ int lines;
+ int input = 0;
+ int spaces = 0;
+ int please_display_more_prompt;
struct stat st;
FILE *file;
- int len, page_height;
+ FILE *cin;
+ int len;
+ unsigned terminal_width;
+ unsigned terminal_height;
-#if defined CONFIG_FEATURE_AUTOWIDTH && defined CONFIG_FEATURE_USE_TERMIOS
- struct winsize win = { 0, 0, 0, 0 };
-#endif
+ INIT_G();
- argc--;
argv++;
-
-
- /* not use inputing from terminal if usage: more > outfile */
- if(isatty(fileno(stdout))) {
- cin = fopen(CURRENT_TTY, "r");
- if (!cin)
- cin = bb_xfopen(CONSOLE_DEV, "r");
- please_display_more_prompt = 0;
-#ifdef CONFIG_FEATURE_USE_TERMIOS
- getTermSettings(fileno(cin), &initial_settings);
- new_settings = initial_settings;
- new_settings.c_lflag &= ~ICANON;
- new_settings.c_lflag &= ~ECHO;
-#ifndef linux
- /* Hmm, in linux c_cc[] not parsed if set ~ICANON */
- new_settings.c_cc[VMIN] = 1;
- new_settings.c_cc[VTIME] = 0;
-#endif
- setTermSettings(fileno(cin), &new_settings);
- atexit(set_tty_to_initial_mode);
- (void) signal(SIGINT, gotsig);
- (void) signal(SIGQUIT, gotsig);
- (void) signal(SIGTERM, gotsig);
+ /* 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_for_read(CURRENT_TTY);
+ 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);
+ bb_signals(0
+ + (1 << SIGINT)
+ + (1 << SIGQUIT)
+ + (1 << SIGTERM)
+ , gotsig);
#endif
- }
do {
- if (argc == 0) {
- file = stdin;
- } else
- file = bb_wfopen(*argv, "r");
- if(file==0)
- goto loop;
-
+ file = stdin;
+ if (*argv) {
+ file = fopen_or_warn(*argv, "r");
+ if (!file)
+ continue;
+ }
st.st_size = 0;
fstat(fileno(file), &st);
- if(please_display_more_prompt>0)
- please_display_more_prompt = 0;
+ please_display_more_prompt = 0;
+ /* never returns w, h <= 1 */
+ get_terminal_width_height(fileno(cin), &terminal_width, &terminal_height);
+ terminal_height -= 1;
-#if defined CONFIG_FEATURE_AUTOWIDTH && defined CONFIG_FEATURE_USE_TERMIOS
- ioctl(fileno(stdout), TIOCGWINSZ, &win);
- if (win.ws_row > 4)
- terminal_height = win.ws_row - 2;
- if (win.ws_col > 0)
- terminal_width = win.ws_col - 1;
-#endif
- len=0;
+ len = 0;
lines = 0;
- page_height = terminal_height;
- while ((c = getc(file)) != EOF) {
-
- if (please_display_more_prompt>0) {
+ while (spaces || (c = getc(file)) != EOF) {
+ int wrap;
+ if (spaces)
+ spaces--;
+ loop_top:
+ if (input != 'r' && please_display_more_prompt) {
len = printf("--More-- ");
- if (file != stdin && st.st_size > 0) {
-#if _FILE_OFFSET_BITS == 64
- len += printf("(%d%% of %lld bytes)",
- (int) (100 * ((double) ftell(file) /
- (double) st.st_size)), (long long)st.st_size);
-#else
- len += printf("(%d%% of %ld bytes)",
- (int) (100 * ((double) ftell(file) /
- (double) st.st_size)), (long)st.st_size);
-#endif
+ if (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);
-#ifndef CONFIG_FEATURE_USE_TERMIOS
- printf("\033[A"); /* up cursor */
+ for (;;) {
+ input = getc(cin);
+ input = tolower(input);
+#if !ENABLE_FEATURE_USE_TERMIOS
+ printf("\033[A"); /* up cursor */
#endif
- /* Erase the "More" message */
- putc('\r', stdout);
- while (--len >= 0)
- putc(' ', stdout);
- putc('\r', stdout);
- fflush(stdout);
- len=0;
+ /* Erase the last message */
+ printf("\r%*s\r", len, "");
+
+ /* Due to various multibyte escape
+ * sequences, it's not ok to accept
+ * any input as a command to scroll
+ * the screen. We only allow known
+ * commands, else we show help msg. */
+ if (input == ' ' || input == '\n' || input == 'q' || input == 'r')
+ break;
+ len = printf("(Enter:next line Space:next page Q:quit R:show the rest)");
+ }
+ len = 0;
lines = 0;
- page_height = terminal_height;
please_display_more_prompt = 0;
if (input == 'q')
goto end;
+
+ /* The user may have resized the terminal.
+ * Re-read the dimensions. */
+#if ENABLE_FEATURE_USE_TERMIOS
+ get_terminal_width_height(cin_fileno, &terminal_width, &terminal_height);
+ terminal_height -= 1;
+#endif
+ }
+
+ /* Crudely convert tabs into spaces, which are
+ * a bajillion times easier to deal with. */
+ if (c == '\t') {
+ spaces = CONVERTED_TAB_SIZE - 1;
+ c = ' ';
}
- /*
+ /*
* 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
+ * 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')
- if(please_display_more_prompt==0)
- 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);
- if (quot) {
- if (rem)
- page_height-=quot;
- else
- page_height-=(quot-1);
- }
- }
- if (++lines >= page_height) {
- if(please_display_more_prompt==0)
+ wrap = (++len > terminal_width);
+ if (c == '\n' || wrap) {
+ /* Then outputting this character
+ * will move us to a new line. */
+ if (++lines >= terminal_height || input == '\n')
please_display_more_prompt = 1;
- }
- len=0;
+ 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);
- len++;
+ if (c != '\n' && wrap) {
+ /* Then outputting this will also put a character on
+ * the beginning of that new line. Thus we first want to
+ * display the prompt (if any), so we skip the putchar()
+ * and go back to the top of the loop, without reading
+ * a new character. */
+ goto loop_top;
+ }
+ /* My small mind cannot fathom backspaces and UTF-8 */
+ putchar(c);
}
fclose(file);
fflush(stdout);
-loop:
- argv++;
- } while (--argc > 0);
- end:
+ } while (*argv && *++argv);
+ end:
+ setTermSettings(cin_fileno, &initial_settings);
return 0;
}
diff --git a/release/src/router/busybox/util-linux/mount.c b/release/src/router/busybox/util-linux/mount.c
index 15a0b576..694057bb 100644
--- a/release/src/router/busybox/util-linux/mount.c
+++ b/release/src/router/busybox/util-linux/mount.c
@@ -3,493 +3,1998 @@
* Mini mount implementation for busybox
*
* Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2005-2006 by Rob Landley <rob@landley.net>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * 3/21/1999 Charles P. Wright <cpwright@cpwright.com>
- * searches through fstab when -a is passed
- * will try mounting stuff with all fses when passed -t auto
- *
- * 1999-04-17 Dave Cinege...Rewrote -t auto. Fixed ro mtab.
- *
- * 1999-10-07 Erik Andersen <andersen@codepoet.org>.
- * Rewrite of a lot of code. Removed mtab usage (I plan on
- * putting it back as a compile-time option some time),
- * major adjustments to option parsing, and some serious
- * dieting all around.
- *
- * 1999-11-06 mtab suppport is back - andersee
- *
- * 2000-01-12 Ben Collins <bcollins@debian.org>, Borrowed utils-linux's
- * mount to add loop support.
- *
- * 2000-04-30 Dave Cinege <dcinege@psychosis.com>
- * Rewrote fstab while loop and lower mount section. Can now do
- * single mounts from fstab. Can override fstab options for single
- * mount. Common mount_one call for single mounts and 'all'. Fixed
- * mtab updating and stale entries. Removed 'remount' default.
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <limits.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
+// 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 <mntent.h>
-#include <ctype.h>
-#include "busybox.h"
+#include <syslog.h>
+#include "libbb.h"
-#ifdef CONFIG_NFSMOUNT
-#if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
-#error "You need to build uClibc with UCLIBC_HAS_RPC for busybox mount with NFS support to compile."
+#if ENABLE_FEATURE_MOUNT_LABEL
+#include "volume_id.h"
+#endif
+
+// Needed for nfs support only
+#include <sys/utsname.h>
+#undef TRUE
+#undef FALSE
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+
+#ifndef MS_SILENT
+#define MS_SILENT (1 << 15)
#endif
+// Grab more as needed from util-linux's mount/mount_constants.h
+#ifndef MS_DIRSYNC
+#define MS_DIRSYNC 128 // Directory modifications are synchronous
#endif
+
+#if defined(__dietlibc__)
+// 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
+// dietlibc-0.30 does not have implementation of getmntent_r()
+static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
+ char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
+{
+ struct mntent* ment = getmntent(stream);
+ return memcpy(result, ment, sizeof(*ment));
+}
+#endif
+
+
+// Not real flags, but we want to be able to check for this.
enum {
- MS_MGC_VAL = 0xc0ed0000, /* Magic number indicatng "new" flags */
- MS_RDONLY = 1, /* Mount read-only */
- MS_NOSUID = 2, /* Ignore suid and sgid bits */
- MS_NODEV = 4, /* Disallow access to device special files */
- MS_NOEXEC = 8, /* Disallow program execution */
- MS_SYNCHRONOUS = 16, /* Writes are synced at once */
- MS_REMOUNT = 32, /* Alter flags of a mounted FS */
- MS_MANDLOCK = 64, /* Allow mandatory locks on an FS */
- S_QUOTA = 128, /* Quota initialized for file/directory/symlink */
- S_APPEND = 256, /* Append-only file */
- S_IMMUTABLE = 512, /* Immutable file */
- MS_NOATIME = 1024, /* Do not update access times. */
- MS_NODIRATIME = 2048, /* Do not update directory access times */
- MS_BIND = 4096, /* Use the new linux 2.4.x "mount --bind" feature */
+ MOUNT_USERS = (1 << 28) * ENABLE_DESKTOP,
+ MOUNT_NOAUTO = (1 << 29),
+ MOUNT_SWAP = (1 << 30),
};
-#if defined CONFIG_FEATURE_MOUNT_LOOP
-#include <fcntl.h>
-#include <sys/ioctl.h>
-static int use_loop = FALSE;
+#define OPTION_STR "o:t:rwanfvsiO:"
+enum {
+ OPT_o = (1 << 0),
+ OPT_t = (1 << 1),
+ OPT_r = (1 << 2),
+ OPT_w = (1 << 3),
+ OPT_a = (1 << 4),
+ OPT_n = (1 << 5),
+ OPT_f = (1 << 6),
+ OPT_v = (1 << 7),
+ OPT_s = (1 << 8),
+ OPT_i = (1 << 9),
+ OPT_O = (1 << 10),
+};
+
+#if ENABLE_FEATURE_MTAB_SUPPORT
+#define useMtab (!(option_mask32 & OPT_n))
+#else
+#define useMtab 0
+#endif
+
+#if ENABLE_FEATURE_MOUNT_FAKE
+#define fakeIt (option_mask32 & OPT_f)
+#else
+#define fakeIt 0
#endif
-extern int mount(__const char *__special_file, __const char *__dir,
- __const char *__fstype, unsigned long int __rwflag,
- __const void *__data);
-extern int umount(__const char *__special_file);
-extern int umount2(__const char *__special_file, int __flags);
-extern int sysfs(int option, unsigned int fs_index, char *buf);
+// 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
+static const int32_t mount_options[] = {
+ // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
+
+ USE_FEATURE_MOUNT_LOOP(
+ /* "loop" */ 0,
+ )
-struct mount_options {
- const char *name;
- unsigned long and;
- unsigned long or;
+ USE_FEATURE_MOUNT_FSTAB(
+ /* "defaults" */ 0,
+ /* "quiet" 0 - do not filter out, vfat wants to see it */
+ /* "noauto" */ MOUNT_NOAUTO,
+ /* "sw" */ MOUNT_SWAP,
+ /* "swap" */ MOUNT_SWAP,
+ USE_DESKTOP(/* "user" */ MOUNT_USERS,)
+ USE_DESKTOP(/* "users" */ MOUNT_USERS,)
+ /* "_netdev" */ 0,
+ )
+
+ 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,
+ /* "dirsync" */ MS_DIRSYNC,
+ /* "async" */ ~MS_SYNCHRONOUS,
+ /* "atime" */ ~MS_NOATIME,
+ /* "noatime" */ MS_NOATIME,
+ /* "diratime" */ ~MS_NODIRATIME,
+ /* "nodiratime" */ MS_NODIRATIME,
+ /* "mand" */ MS_MANDLOCK,
+ /* "nomand" */ ~MS_MANDLOCK,
+ /* "relatime" */ MS_RELATIME,
+ /* "norelatime" */ ~MS_RELATIME,
+ /* "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
};
-static const struct mount_options mount_options[] = {
- {"async", ~MS_SYNCHRONOUS, 0},
- {"atime", ~0, ~MS_NOATIME},
- {"defaults", ~0, 0},
- {"noauto", ~0, 0},
- {"dev", ~MS_NODEV, 0},
- {"diratime", ~0, ~MS_NODIRATIME},
- {"exec", ~MS_NOEXEC, 0},
- {"noatime", ~0, MS_NOATIME},
- {"nodev", ~0, MS_NODEV},
- {"nodiratime", ~0, MS_NODIRATIME},
- {"noexec", ~0, MS_NOEXEC},
- {"nosuid", ~0, MS_NOSUID},
- {"remount", ~0, MS_REMOUNT},
- {"ro", ~0, MS_RDONLY},
- {"rw", ~MS_RDONLY, 0},
- {"suid", ~MS_NOSUID, 0},
- {"sync", ~0, MS_SYNCHRONOUS},
- {"bind", ~0, MS_BIND},
- {0, 0, 0}
+static const char mount_option_str[] =
+ USE_FEATURE_MOUNT_LOOP(
+ "loop\0"
+ )
+ USE_FEATURE_MOUNT_FSTAB(
+ "defaults\0"
+ // "quiet\0" - do not filter out, vfat wants to see it
+ "noauto\0"
+ "sw\0"
+ "swap\0"
+ USE_DESKTOP("user\0")
+ USE_DESKTOP("users\0")
+ "_netdev\0"
+ )
+ USE_FEATURE_MOUNT_FLAGS(
+ // vfs flags
+ "nosuid\0"
+ "suid\0"
+ "dev\0"
+ "nodev\0"
+ "exec\0"
+ "noexec\0"
+ "sync\0"
+ "dirsync\0"
+ "async\0"
+ "atime\0"
+ "noatime\0"
+ "diratime\0"
+ "nodiratime\0"
+ "mand\0"
+ "nomand\0"
+ "relatime\0"
+ "norelatime\0"
+ "loud\0"
+
+ // action flags
+ "bind\0"
+ "move\0"
+ "shared\0"
+ "slave\0"
+ "private\0"
+ "unbindable\0"
+ "rshared\0"
+ "rslave\0"
+ "rprivate\0"
+ "runbindable\0"
+ )
+
+ // Always understood.
+ "ro\0" // vfs flag
+ "rw\0" // vfs flag
+ "remount\0" // action flag
+;
+
+
+struct globals {
+#if ENABLE_FEATURE_MOUNT_NFS
+ smalluint nfs_mount_version;
+#endif
+#if ENABLE_FEATURE_MOUNT_VERBOSE
+ unsigned verbose;
+#endif
+ llist_t *fslist;
+ char getmntent_buf[1];
+
};
+enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define nfs_mount_version (G.nfs_mount_version)
+#if ENABLE_FEATURE_MOUNT_VERBOSE
+#define verbose (G.verbose )
+#else
+#define verbose 0
+#endif
+#define fslist (G.fslist )
+#define getmntent_buf (G.getmntent_buf )
+
-static int
-do_mount(char *specialfile, char *dir, char *filesystemtype, long flags,
- void *string_flags, int useMtab, int fakeIt, char *mtab_opts,
- int mount_all)
+#if ENABLE_FEATURE_MOUNT_VERBOSE
+static int verbose_mount(const char *source, const char *target,
+ const char *filesystemtype,
+ unsigned long mountflags, const void *data)
{
- int status = 0;
+ int rc;
-#if defined CONFIG_FEATURE_MOUNT_LOOP
- char *lofile = NULL;
+ errno = 0;
+ rc = mount(source, target, filesystemtype, mountflags, data);
+ if (verbose >= 2)
+ bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
+ source, target, filesystemtype,
+ mountflags, (char*)data, rc);
+ return rc;
+}
+#else
+#define verbose_mount(...) mount(__VA_ARGS__)
#endif
- if (!fakeIt) {
-#if defined CONFIG_FEATURE_MOUNT_LOOP
- if (use_loop == TRUE) {
- int loro = flags & MS_RDONLY;
+#if ENABLE_FEATURE_MOUNT_LABEL
+static void resolve_mount_spec(char **fsname)
+{
+ char *tmp = NULL;
- lofile = specialfile;
+ if (!strncmp(*fsname, "UUID=", 5))
+ tmp = get_devname_from_uuid(*fsname + 5);
+ else if (!strncmp(*fsname, "LABEL=", 6))
+ tmp = get_devname_from_label(*fsname + 6);
- specialfile = find_unused_loop_device();
- if (specialfile == NULL) {
- bb_error_msg_and_die("Could not find a spare loop device");
- }
- if (set_loop(specialfile, lofile, 0, &loro)) {
- bb_error_msg_and_die("Could not setup loop device");
+ if (tmp)
+ *fsname = tmp;
+}
+#else
+#define resolve_mount_spec(fsname) ((void)0)
+#endif
+
+// 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++;
}
- if (!(flags & MS_RDONLY) && loro) { /* loop is ro, but wanted rw */
- bb_error_msg("WARNING: loop device is read-only");
- flags |= MS_RDONLY;
+ 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 long parse_mount_options(char *options, char **unrecognized)
+{
+ long flags = MS_SILENT;
+
+ // Loop through options
+ for (;;) {
+ unsigned i;
+ char *comma = strchr(options, ',');
+ const char *option_str = mount_option_str;
+
+ if (comma) *comma = '\0';
+
+// FIXME: use hasmntopt()
+ // Find this option in mount_options
+ for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
+ if (!strcasecmp(option_str, options)) {
+ long fl = mount_options[i];
+ if (fl < 0) flags &= fl;
+ else flags |= fl;
+ break;
}
+ option_str += strlen(option_str) + 1;
+ }
+ // If unrecognized not NULL, append unrecognized mount options
+ if (unrecognized && i == ARRAY_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);
+ }
+
+ if (!comma)
+ break;
+ // Advance to next option
+ *comma = ',';
+ options = ++comma;
+ }
+
+ return flags;
+}
+
+// Return a list of all block device backed filesystems
+static llist_t *get_block_backed_filesystems(void)
+{
+ static const char filesystems[2][sizeof("/proc/filesystems")] = {
+ "/etc/filesystems",
+ "/proc/filesystems",
+ };
+ char *fs, *buf;
+ llist_t *list = 0;
+ int i;
+ FILE *f;
+
+ for (i = 0; i < 2; i++) {
+ f = fopen_for_read(filesystems[i]);
+ if (!f) continue;
+
+ while ((buf = xmalloc_fgetline(f)) != NULL) {
+ 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;
+}
+
+#if ENABLE_FEATURE_CLEAN_UP
+static void delete_block_backed_filesystems(void)
+{
+ llist_free(fslist, free);
+}
+#else
+void delete_block_backed_filesystems(void);
#endif
- status = mount(specialfile, dir, filesystemtype, flags, string_flags);
- if (status < 0 && errno == EROFS) {
+
+// 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, long vfsflags, char *filteropts)
+{
+ int rc = 0;
+
+ if (fakeIt) {
+ if (verbose >= 2)
+ bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
+ mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
+ vfsflags, filteropts);
+ goto mtab;
+ }
+
+ // Mount, with fallback to read-only if necessary.
+ for (;;) {
+ errno = 0;
+ rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
+ vfsflags, filteropts);
+
+ // If mount failed, try
+ // helper program mount.<mnt_type>
+ if (ENABLE_FEATURE_MOUNT_HELPERS && rc) {
+ char *args[6];
+ int errno_save = errno;
+ args[0] = xasprintf("mount.%s", mp->mnt_type);
+ rc = 1;
+ args[rc++] = mp->mnt_fsname;
+ args[rc++] = mp->mnt_dir;
+ if (filteropts) {
+ args[rc++] = (char *)"-o";
+ args[rc++] = filteropts;
+ }
+ args[rc] = NULL;
+ rc = wait4pid(spawn(args));
+ free(args[0]);
+ if (!rc)
+ break;
+ errno = errno_save;
+ }
+
+ if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
+ break;
+ if (!(vfsflags & MS_SILENT))
bb_error_msg("%s is write-protected, mounting read-only",
- specialfile);
- status = mount(specialfile, dir, filesystemtype, flags |=
- MS_RDONLY, string_flags);
+ 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 (useMtab && !rc && !(vfsflags & MS_REMOUNT)) {
+ char *fsname;
+ FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
+ const char *option_str = mount_option_str;
+ int i;
+
+ if (!mountTable) {
+ bb_error_msg("no %s", bb_path_mtab_file);
+ goto ret;
}
- /* Don't whine about already mounted filesystems when mounting all. */
- if (status < 0 && errno == EBUSY && mount_all) {
- return TRUE;
+
+ // Add vfs string flags
+
+ for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
+ if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
+ append_mount_options(&(mp->mnt_opts), option_str);
+ option_str += strlen(option_str) + 1;
}
- }
+ // 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';
- /* If the mount was sucessful, do anything needed, then return TRUE */
- if (status == 0 || fakeIt == TRUE) {
+ // Convert to canonical pathnames as needed
-#if defined CONFIG_FEATURE_MTAB_SUPPORT
- if (useMtab) {
- erase_mtab(specialfile); /* Clean any stale entries */
- write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts);
+ 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 Mickiewicz <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
- return (TRUE);
+};
+
+/*
+ * 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 */
+ NFS_MOUNT_NORDIRPLUS = 0x4000
+};
+
+
+/*
+ * 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 {
+ short stat;
+ short 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;
+
+ for (i = 0; nfs_errtbl[i].stat != -1; i++) {
+ if (nfs_errtbl[i].stat == status)
+ return strerror(nfs_errtbl[i].errnum);
}
+ return xasprintf("unknown nfs status return value: %d", status);
+}
- /* Bummer. mount failed. Clean up */
-#if defined CONFIG_FEATURE_MOUNT_LOOP
- if (lofile != NULL) {
- del_loop(specialfile);
+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;
}
-#endif
+ return TRUE;
+}
- if (errno == EPERM) {
- bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+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;
+}
- return (FALSE);
+#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
+
+/*
+ * 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)
+{
+ int kernel_version;
+
+ if (nfs_mount_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 void
+get_mountport(struct pmap *pm_mnt,
+ struct sockaddr_in *server_addr,
+ long unsigned prog,
+ long unsigned version,
+ long unsigned proto,
+ long unsigned port)
+{
+ struct pmaplist *pmap;
+
+ 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;
+ pm_mnt->pm_prog = prog;
+ pm_mnt->pm_vers = version;
+ pm_mnt->pm_prot = proto;
+ pm_mnt->pm_port = port;
-static void paste_str(char **s1, const char *s2)
+ while (pmap) {
+ if (pmap->pml_map.pm_prog != prog)
+ goto next;
+ if (!version && pm_mnt->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 && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto) ||
+ (port && pmap->pml_map.pm_port != port))
+ goto next;
+ memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
+ next:
+ pmap = pmap->pml_next;
+ }
+ if (!pm_mnt->pm_vers)
+ pm_mnt->pm_vers = MOUNTVERS;
+ if (!pm_mnt->pm_port)
+ pm_mnt->pm_port = MOUNTPORT;
+ if (!pm_mnt->pm_prot)
+ pm_mnt->pm_prot = IPPROTO_TCP;
+}
+
+#if BB_MMU
+static int daemonize(void)
{
- *s1 = xrealloc(*s1, strlen(*s1) + strlen(s2) + 1);
- strcat(*s1, s2);
+ int pid = fork();
+ if (pid < 0) /* error */
+ return -errno;
+ if (pid > 0) /* parent */
+ return 0;
+ /* child */
+ close(0);
+ xopen(bb_dev_null, O_RDWR);
+ xdup2(0, 1);
+ xdup2(0, 2);
+ setsid();
+ openlog(applet_name, LOG_PID, LOG_DAEMON);
+ logmode = LOGMODE_SYSLOG;
+ return 1;
}
+#else
+static inline int daemonize(void) { return -ENOSYS; }
+#endif
-/* Seperate standard mount options from the nonstandard string options */
-static void parse_mount_options(char *options, int *flags, char **strflags)
+/* TODO */
+static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
{
- while (options) {
- int gotone = FALSE;
- char *comma = strchr(options, ',');
- const struct mount_options *f = mount_options;
+ 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, long 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;
+#if BB_MMU
+ smallint bg = 0;
+#else
+ enum { bg = 0 };
+#endif
+ int retry;
+ int mountprog;
+ int mountvers;
+ int nfsprog;
+ int nfsvers;
+ int retval;
+ /* these all are one-bit really. 4.3.1 likes this combination: */
+ smallint tcp;
+ smallint soft;
+ int intr;
+ int posix;
+ int nocto;
+ int noac;
+ int nordirplus;
+ int nolock;
+
+ find_kernel_nfs_mount_version();
- if (comma) {
- *comma = '\0';
+ 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 ((size_t)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);
+ }
- while (f->name != 0) {
- if (strcasecmp(f->name, options) == 0) {
+ memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
- *flags &= f->and;
- *flags |= f->or;
- gotone = TRUE;
- break;
+ /* 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;
+
+ soft = 0;
+ intr = 0;
+ posix = 0;
+ nocto = 0;
+ nolock = 0;
+ noac = 0;
+ nordirplus = 0;
+ retry = 10000; /* 10000 minutes ~ 1 week */
+ tcp = 0;
+
+ mountprog = MOUNTPROG;
+ mountvers = 0;
+ port = 0;
+ mountport = 0;
+ nfsprog = 100003;
+ nfsvers = 0;
+
+ /* parse options */
+ if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
+ char *opteq = strchr(opt, '=');
+ if (opteq) {
+ int val, idx;
+ static const char options[] ALIGN1 =
+ /* 0 */ "rsize\0"
+ /* 1 */ "wsize\0"
+ /* 2 */ "timeo\0"
+ /* 3 */ "retrans\0"
+ /* 4 */ "acregmin\0"
+ /* 5 */ "acregmax\0"
+ /* 6 */ "acdirmin\0"
+ /* 7 */ "acdirmax\0"
+ /* 8 */ "actimeo\0"
+ /* 9 */ "retry\0"
+ /* 10 */ "port\0"
+ /* 11 */ "mountport\0"
+ /* 12 */ "mounthost\0"
+ /* 13 */ "mountprog\0"
+ /* 14 */ "mountvers\0"
+ /* 15 */ "nfsprog\0"
+ /* 16 */ "nfsvers\0"
+ /* 17 */ "vers\0"
+ /* 18 */ "proto\0"
+ /* 19 */ "namlen\0"
+ /* 20 */ "addr\0";
+
+ *opteq++ = '\0';
+ idx = index_in_strings(options, opt);
+ switch (idx) {
+ case 12: // "mounthost"
+ mounthost = xstrndup(opteq,
+ strcspn(opteq, " \t\n\r,"));
+ continue;
+ case 18: // "proto"
+ if (!strncmp(opteq, "tcp", 3))
+ tcp = 1;
+ else if (!strncmp(opteq, "udp", 3))
+ tcp = 0;
+ else
+ bb_error_msg("warning: unrecognized proto= option");
+ continue;
+ case 20: // "addr" - ignore
+ continue;
+ }
+
+ val = xatoi_u(opteq);
+ switch (idx) {
+ case 0: // "rsize"
+ data.rsize = val;
+ continue;
+ case 1: // "wsize"
+ data.wsize = val;
+ continue;
+ case 2: // "timeo"
+ data.timeo = val;
+ continue;
+ case 3: // "retrans"
+ data.retrans = val;
+ continue;
+ case 4: // "acregmin"
+ data.acregmin = val;
+ continue;
+ case 5: // "acregmax"
+ data.acregmax = val;
+ continue;
+ case 6: // "acdirmin"
+ data.acdirmin = val;
+ continue;
+ case 7: // "acdirmax"
+ data.acdirmax = val;
+ continue;
+ case 8: // "actimeo"
+ data.acregmin = val;
+ data.acregmax = val;
+ data.acdirmin = val;
+ data.acdirmax = val;
+ continue;
+ case 9: // "retry"
+ retry = val;
+ continue;
+ case 10: // "port"
+ port = val;
+ continue;
+ case 11: // "mountport"
+ mountport = val;
+ continue;
+ case 13: // "mountprog"
+ mountprog = val;
+ continue;
+ case 14: // "mountvers"
+ mountvers = val;
+ continue;
+ case 15: // "nfsprog"
+ nfsprog = val;
+ continue;
+ case 16: // "nfsvers"
+ case 17: // "vers"
+ nfsvers = val;
+ continue;
+ case 19: // "namlen"
+ //if (nfs_mount_version >= 2)
+ data.namlen = val;
+ //else
+ // bb_error_msg("warning: option namlen is not supported\n");
+ continue;
+ default:
+ bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
+ goto fail;
}
- f++;
- }
-#if defined CONFIG_FEATURE_MOUNT_LOOP
- if (!strcasecmp("loop", options)) { /* loop device support */
- use_loop = TRUE;
- gotone = TRUE;
}
+ else { /* not of the form opt=val */
+ static const char options[] ALIGN1 =
+ "bg\0"
+ "fg\0"
+ "soft\0"
+ "hard\0"
+ "intr\0"
+ "posix\0"
+ "cto\0"
+ "ac\0"
+ "tcp\0"
+ "udp\0"
+ "lock\0"
+ "rdirplus\0";
+ int val = 1;
+ if (!strncmp(opt, "no", 2)) {
+ val = 0;
+ opt += 2;
+ }
+ switch (index_in_strings(options, opt)) {
+ case 0: // "bg"
+#if BB_MMU
+ bg = val;
+#endif
+ break;
+ case 1: // "fg"
+#if BB_MMU
+ bg = !val;
#endif
- if (!gotone) {
- if (**strflags) {
- /* have previous parsed options */
- paste_str(strflags, ",");
+ 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;
+ case 11: //rdirplus
+ nordirplus = !val;
+ break;
+ default:
+ bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
+ goto fail;
}
- paste_str(strflags, options);
}
- if (comma) {
- *comma = ',';
- options = ++comma;
+ }
+ 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)
+ | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 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();
+ 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 {
- break;
+ hp = gethostbyname(mounthost);
+ if (hp == NULL) {
+ bb_herror_msg("%s", mounthost);
+ goto fail;
+ }
+ if ((size_t)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);
}
}
-}
-static int mount_one(char *blockDevice, char *directory, char *filesystemType,
- unsigned long flags, char *string_flags, int useMtab,
- int fakeIt, char *mtab_opts, int whineOnErrors,
- int mount_all)
-{
- int status = 0;
- if (strcmp(filesystemType, "auto") == 0) {
- char buf[255];
- FILE *f;
- int read_proc = 0;
-
- f = fopen("/etc/filesystems", "r");
-
- if (f) {
- while (fgets(buf, sizeof(buf), f)) {
- if (*buf == '*') {
- read_proc = 1;
- } else if (*buf == '#') {
- continue;
- } else {
- filesystemType = buf;
-
- /* Add NULL termination to each line */
- while (*filesystemType && !isspace(*filesystemType)) {
- filesystemType++;
- }
- *filesystemType = '\0';
-
- filesystemType = buf;
-
- if (bb_strlen(filesystemType)) {
- status =
- do_mount(blockDevice, directory, filesystemType,
- flags | MS_MGC_VAL, string_flags,
- useMtab, fakeIt, mtab_opts, mount_all);
- if (status) {
- break;
- }
- }
+ /*
+ * 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;
+/* FIXME: use monotonic()? */
+ 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);
+
+ get_mountport(&pm_mnt, &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 = NULL;
+ }
+ 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 = NULL;
+ close(msock);
+ msock = -1;
+ }
+
+ /* 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;
}
- fclose(f);
}
+ 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);
- if ((!f || read_proc) && !status) {
- f = bb_xfopen("/proc/filesystems", "r");
+ data.flags |= NFS_MOUNT_VER3;
+ }
- while (fgets(buf, sizeof(buf), f) != NULL) {
- filesystemType = buf;
- if (*filesystemType == '\t') { /* Not a nodev filesystem */
+ /* 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);
- /* Add NULL termination to each line */
- while (*filesystemType && *filesystemType != '\n') {
- filesystemType++;
- }
- *filesystemType = '\0';
+ /* 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));
- filesystemType = buf;
- filesystemType++; /* hop past tab */
+ /* Clean up */
+ auth_destroy(mclient->cl_auth);
+ clnt_destroy(mclient);
+ close(msock);
+ msock = -1;
- status =
- do_mount(blockDevice, directory, filesystemType,
- flags | MS_MGC_VAL, string_flags, useMtab,
- fakeIt, mtab_opts, mount_all);
- if (status) {
- break;
- }
+ 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 */
+/* FIXME: parent doesn't close fsock - ??! */
+ retval = -daemonized;
+ goto ret;
}
}
+ sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
+ delay *= 2;
+ if (delay > 30)
+ delay = 30;
}
- fclose(f);
- } else {
- status =
- do_mount(blockDevice, directory, filesystemType,
- flags | MS_MGC_VAL, string_flags, useMtab, fakeIt,
- mtab_opts, mount_all);
}
- if (!status) {
- if (whineOnErrors) {
- bb_perror_msg("Mounting %s on %s failed", blockDevice, directory);
+ /* Perform actual mount */
+ do_mount:
+ mp->mnt_type = (char*)"nfs";
+ retval = mount_it_now(mp, vfsflags, (char*)&data);
+ goto ret;
+
+ /* Abort */
+ fail:
+ if (msock >= 0) {
+ if (mclient) {
+ auth_destroy(mclient->cl_auth);
+ clnt_destroy(mclient);
}
- return (FALSE);
+ close(msock);
}
- return (TRUE);
+ if (fsock >= 0)
+ close(fsock);
+
+ ret:
+ free(hostname);
+ free(mounthost);
+ free(filteropts);
+ return retval;
}
-static void show_mounts(char *onlytype)
+#else // !ENABLE_FEATURE_MOUNT_NFS
+
+// Never called. Call should be optimized out.
+int nfsmount(struct mntent *mp, long 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)
{
- FILE *mountTable = setmntent(bb_path_mtab_file, "r");
+ int rc = -1;
+ long vfsflags;
+ char *loopFile = 0, *filteropts = 0;
+ llist_t *fl = 0;
+ struct stat st;
- if (mountTable) {
- struct mntent *m;
+ vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
- while ((m = getmntent(mountTable)) != 0) {
- char *blockDevice = m->mnt_fsname;
+ // Treat fstype "auto" as unspecified
+ if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
+ mp->mnt_type = NULL;
- if (strcmp(blockDevice, "rootfs") == 0) {
- continue;
- } else if (strcmp(blockDevice, "/dev/root") == 0) {
- blockDevice = find_real_root_device_name(blockDevice);
- }
- if (!onlytype || (strcmp(m->mnt_type, onlytype) == 0)) {
- printf("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir,
- m->mnt_type, m->mnt_opts);
- }
-#ifdef CONFIG_FEATURE_CLEAN_UP
- if (blockDevice != m->mnt_fsname) {
- free(blockDevice);
+ // Might this be a virtual filesystem?
+ if (ENABLE_FEATURE_MOUNT_HELPERS
+ && (strchr(mp->mnt_fsname, '#'))
+ ) {
+ char *s, *p, *args[35];
+ int n = 0;
+// FIXME: does it allow execution of arbitrary commands?!
+// What args[0] can end up with?
+ for (s = p = mp->mnt_fsname; *s && n < 35-3; ++s) {
+ if (s[0] == '#' && s[1] != '#') {
+ *s = '\0';
+ args[n++] = p;
+ p = s + 1;
}
+ }
+ args[n++] = p;
+ args[n++] = mp->mnt_dir;
+ args[n] = NULL;
+ rc = wait4pid(xspawn(args));
+ goto report_error;
+ }
+
+ // 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]
+ ) {
+#if 0 /* reported to break things */
+ len_and_sockaddr *lsa;
+ char *ip, *dotted;
+ char *s;
+
+ // 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->u.sa);
+ 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);
#endif
+ // Lock is required [why?]
+ vfsflags |= MS_MANDLOCK;
+ mp->mnt_type = (char*)"cifs";
+ rc = mount_it_now(mp, vfsflags, filteropts);
+#if 0
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(mp->mnt_fsname);
+ free(ip);
+ free(dotted);
+ free(lsa);
+ }
+#endif
+ 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.)
+ // (We use stat, not lstat, in order to allow
+ // mount symlink_to_file_or_blkdev dir)
+ if (!stat(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 = NULL; // will receive malloced loop dev name
+ if (set_loop(&(mp->mnt_fsname), loopFile, 0) < 0) {
+ if (errno == EPERM || errno == EACCES)
+ bb_error_msg(bb_msg_perm_denied_are_you_root);
+ else
+ bb_perror_msg("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);
}
- endmntent(mountTable);
- } else {
- bb_perror_msg_and_die(bb_path_mtab_file);
}
- exit(EXIT_SUCCESS);
+
+ report_error:
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(filteropts);
+
+ if (errno == EBUSY && ignore_busy)
+ return 0;
+ if (rc < 0)
+ bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
+ return rc;
}
-extern int mount_main(int argc, char **argv)
+/* -O support
+ * Unlike -t, -O should interpret "no" prefix differently:
+ * -t noa,b,c = -t no(a,b,c) = mount all except fs'es with types a,b, and c
+ * -O noa,b,c = -O noa,b,c = mount all with without option a,
+ * or with option b or c.
+ * But for now we do not support -O a,b,c at all (only -O a).
+ *
+ * Another difference from -t support (match_fstype) is that
+ * we need to examine the _list_ of options in fsopt, not just a string.
+ */
+static int match_opt(const char *fs_opt, const char *O_opt)
{
- struct stat statbuf;
- char *string_flags = bb_xstrdup("");
- char *extra_opts;
- int flags = 0;
- char *filesystemType = "auto";
- int got_filesystemType = 0;
- char *device = xmalloc(PATH_MAX);
- char *directory = xmalloc(PATH_MAX);
- struct mntent *m = NULL;
- int all = FALSE;
- int fakeIt = FALSE;
- int useMtab = TRUE;
- int rc = EXIT_FAILURE;
- FILE *f = 0;
- int opt;
-
- /* Parse options */
- while ((opt = getopt(argc, argv, "o:rt:wafnv")) > 0) {
- switch (opt) {
- case 'o':
- parse_mount_options(optarg, &flags, &string_flags);
- break;
- case 'r':
- flags |= MS_RDONLY;
- break;
- case 't':
- filesystemType = optarg;
- got_filesystemType = 1;
- break;
- case 'w':
- flags &= ~MS_RDONLY;
- break;
- case 'a':
- all = TRUE;
- break;
- case 'f':
- fakeIt = TRUE;
- break;
-#ifdef CONFIG_FEATURE_MTAB_SUPPORT
- case 'n':
- useMtab = FALSE;
- break;
-#endif
- case 'v':
- break; /* ignore -v */
+ int match = 1;
+ int len;
+
+ if (!O_opt)
+ return match;
+
+ if (O_opt[0] == 'n' && O_opt[1] == 'o') {
+ match--;
+ O_opt += 2;
+ }
+
+ len = strlen(O_opt);
+ while (1) {
+ if (strncmp(fs_opt, O_opt, len) == 0
+ && (fs_opt[len] == '\0' || fs_opt[len] == ',')
+ ) {
+ return match;
}
+ fs_opt = strchr(fs_opt, ',');
+ if (!fs_opt)
+ break;
+ fs_opt++;
}
- if (!all && (optind == argc)) {
- show_mounts(got_filesystemType ? filesystemType : NULL);
+ return !match;
+}
+
+// Parse options, if necessary parse fstab/mtab, and call singlemount for
+// each directory to be mounted.
+static const char must_be_root[] ALIGN1 = "you must be root";
+
+int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mount_main(int argc UNUSED_PARAM, char **argv)
+{
+ char *cmdopts = xzalloc(1);
+ char *fstype = NULL;
+ char *O_optmatch = NULL;
+ char *storage_path;
+ llist_t *lst_o = NULL;
+ 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 = ) sanitize_env_if_suid();
+
+ // Parse long options, like --bind and --move. Note that -o option
+ // and --option are synonymous. Yes, this means --remount,rw works.
+ for (i = j = 1; argv[i]; i++) {
+ if (argv[i][0] == '-' && argv[i][1] == '-')
+ append_mount_options(&cmdopts, argv[i] + 2);
+ else
+ argv[j++] = argv[i];
}
+ argv[j] = NULL;
- if (optind < argc) {
- /* if device is a filename get its real path */
- if (stat(argv[optind], &statbuf) == 0) {
- char *tmp = bb_simplify_path(argv[optind]);
+ // Parse remaining options
+ // Max 2 params; -o is a list, -v is a counter
+ opt_complementary = "?2o::" USE_FEATURE_MOUNT_VERBOSE("vv");
+ opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
+ USE_FEATURE_MOUNT_VERBOSE(, &verbose));
+ while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
+ if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
+ if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
+ argv += optind;
- safe_strncpy(device, tmp, PATH_MAX);
- } else {
- safe_strncpy(device, argv[optind], PATH_MAX);
+ // If we have no arguments, show currently mounted filesystems
+ if (!argv[0]) {
+ if (!(opt & OPT_a)) {
+ 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[0], getmntent_buf,
+ GETMNTENT_BUFSIZE))
+ {
+ // 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;
}
+ storage_path = NULL;
+ } else {
+ // 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 (argv[1]) {
+ 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;
+ resolve_mount_spec(&mtpair->mnt_fsname);
+ rc = singlemount(mtpair, 0);
+ return rc;
+ }
+ storage_path = bb_simplify_path(argv[0]); // malloced
}
- if (optind + 1 < argc)
- directory = bb_simplify_path(argv[optind + 1]);
+ // Past this point, we are handling either "mount -a [opts]"
+ // or "mount [opts] single_param"
- if (all || optind + 1 == argc) {
- f = setmntent("/etc/fstab", "r");
+ i = parse_mount_options(cmdopts, NULL); // FIXME: should be "long", not "int"
+ if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
+ bb_error_msg_and_die(must_be_root);
- if (f == NULL)
- bb_perror_msg_and_die("\nCannot read /etc/fstab");
+ // 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))
+ ) {
+ // verbose_mount(source, target, type, flags, data)
+ rc = verbose_mount("", argv[0], "", i, "");
+ if (rc)
+ bb_simple_perror_msg_and_die(argv[0]);
+ return rc;
+ }
+
+ // Open either fstab or mtab
+ fstabname = "/etc/fstab";
+ if (i & MS_REMOUNT) {
+ // WARNING. I am not sure this matches util-linux's
+ // behavior. It's possible util-linux does not
+ // take -o opts from mtab (takes only mount source).
+ fstabname = bb_path_mtab_file;
+ }
+ fstab = setmntent(fstabname, "r");
+ if (!fstab)
+ bb_perror_msg_and_die("cannot read %s", fstabname);
- while ((m = getmntent(f)) != NULL) {
- if (!all && (optind + 1 == argc)
- && ((strcmp(device, m->mnt_fsname) != 0)
- && (strcmp(device, m->mnt_dir) != 0))) {
+ // Loop through entries until we find what we're looking for
+ memset(mtpair, 0, sizeof(mtpair));
+ for (;;) {
+ struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
+
+ // Get next fstab entry
+ if (!getmntent_r(fstab, mtcur, getmntent_buf
+ + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
+ GETMNTENT_BUFSIZE/2)
+ ) { // End of fstab/mtab is reached
+ mtcur = mtother; // the thing we found last time
+ break;
+ }
+
+ // If we're trying to mount something specific and this isn't it,
+ // skip it. Note we must match the exact text in fstab (ala
+ // "proc") or a full path from root
+ if (argv[0]) {
+
+ // 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 = mtother;
+
+ // If we're mounting all
+ } else {
+ // No, mount -a won't mount anything,
+ // even user mounts, for mere humans
+ if (nonroot)
+ bb_error_msg_and_die(must_be_root);
+
+ // Does type match? (NULL matches always)
+ if (!match_fstype(mtcur, fstype))
continue;
- }
- if (all && ( /* If we're mounting 'all' */
- (strstr(m->mnt_opts, "noauto")) || /* and the file system isn't noauto, */
- (strstr(m->mnt_type, "swap")))) /* and isn't swap, then mount it */
- {
+ // Skip noauto and swap anyway.
+ if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
+ // swap is bogus "fstype", parse_mount_options can't check fstypes
+ || strcasecmp(mtcur->mnt_type, "swap") == 0
+ ) {
continue;
}
- if (all || flags == 0) { /* Allow single mount to override fstab flags */
- flags = 0;
- string_flags[0] = 0;
- parse_mount_options(m->mnt_opts, &flags, &string_flags);
- }
+ // Does (at least one) option match?
+ // (NULL matches always)
+ if (!match_opt(mtcur->mnt_opts, O_optmatch))
+ continue;
- strcpy(device, m->mnt_fsname);
- strcpy(directory, m->mnt_dir);
- filesystemType = bb_xstrdup(m->mnt_type);
- singlemount:
- extra_opts = string_flags;
- rc = EXIT_SUCCESS;
-#ifdef CONFIG_NFSMOUNT
- if (strchr(device, ':') != NULL) {
- filesystemType = "nfs";
- if (nfsmount
- (device, directory, &flags, &extra_opts, &string_flags,
- 1)) {
- bb_perror_msg("nfsmount failed");
- rc = EXIT_FAILURE;
- }
- }
-#endif
- if (!mount_one
- (device, directory, filesystemType, flags, string_flags,
- useMtab, fakeIt, extra_opts, TRUE, all)) {
- rc = EXIT_FAILURE;
- }
- if (!all) {
- break;
+ resolve_mount_spec(&mtcur->mnt_fsname);
+
+ // NFS mounts want this to be xrealloc-able
+ mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
+
+ // Mount this thing
+ if (singlemount(mtcur, 1)) {
+ // Count number of failed mounts
+ rc++;
}
+ free(mtcur->mnt_opts);
}
- if (f) {
- endmntent(f);
+ }
+
+ // End of fstab/mtab is reached.
+ // Were we looking for something specific?
+ if (argv[0]) {
+ long l;
+
+ // If we didn't find anything, complain
+ if (!mtcur->mnt_fsname)
+ bb_error_msg_and_die("can't find %s in %s",
+ argv[0], fstabname);
+
+ // What happens when we try to "mount swap_partition"?
+ // (fstab containts "swap_partition swap swap defaults 0 0")
+ // util-linux-ng 2.13.1 does this:
+ // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
+ // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
+ // lstat("swap", 0x7fff62a3a640) = -1 ENOENT (No such file or directory)
+ // write(2, "mount: mount point swap does not exist\n", 39) = 39
+ // exit_group(32) = ?
+#if 0
+ // In case we want to simply skip swap partitions:
+ l = parse_mount_options(mtcur->mnt_opts, NULL);
+ if ((l & MOUNT_SWAP)
+ // swap is bogus "fstype", parse_mount_options can't check fstypes
+ || strcasecmp(mtcur->mnt_type, "swap") == 0
+ ) {
+ goto ret;
}
- if (!all && f && m == NULL) {
- fprintf(stderr, "Can't find %s in /etc/fstab\n", device);
+#endif
+ if (nonroot) {
+ // fstab must have "users" or "user"
+ l = parse_mount_options(mtcur->mnt_opts, NULL);
+ if (!(l & MOUNT_USERS))
+ bb_error_msg_and_die(must_be_root);
}
- return rc;
+
+ // Mount the last thing we found
+ mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
+ append_mount_options(&(mtcur->mnt_opts), cmdopts);
+ resolve_mount_spec(&mtpair->mnt_fsname);
+ rc = singlemount(mtcur, 0);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(mtcur->mnt_opts);
}
- goto singlemount;
+ //ret:
+ if (ENABLE_FEATURE_CLEAN_UP)
+ endmntent(fstab);
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(storage_path);
+ free(cmdopts);
+ }
+ return rc;
}
diff --git a/release/src/router/busybox/util-linux/nfsmount.c b/release/src/router/busybox/util-linux/nfsmount.c
deleted file mode 100644
index 0edfdf34..00000000
--- a/release/src/router/busybox/util-linux/nfsmount.c
+++ /dev/null
@@ -1,1024 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * nfsmount.c -- Linux NFS mount
- * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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.
- */
-
-/*
- * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
- */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <netdb.h>
-#include <sys/socket.h>
-#include <time.h>
-#include <sys/utsname.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdlib.h>
-#include "busybox.h"
-#undef TRUE
-#undef FALSE
-#include <rpc/rpc.h>
-#include <rpc/pmap_prot.h>
-#include <rpc/pmap_clnt.h>
-#include "nfsmount.h"
-
-
-/*
- * NFS stats. The good thing with these values is that NFSv3 errors are
- * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
- * no-one uses anyway), so we can happily mix code as long as we make sure
- * no NFSv3 errors are returned to NFSv2 clients.
- * Error codes that have a `--' in the v2 column are not part of the
- * standard, but seem to be widely used nevertheless.
- */
-enum nfs_stat {
- NFS_OK = 0, /* v2 v3 */
- NFSERR_PERM = 1, /* v2 v3 */
- NFSERR_NOENT = 2, /* v2 v3 */
- NFSERR_IO = 5, /* v2 v3 */
- NFSERR_NXIO = 6, /* v2 v3 */
- NFSERR_EAGAIN = 11, /* v2 v3 */
- NFSERR_ACCES = 13, /* v2 v3 */
- NFSERR_EXIST = 17, /* v2 v3 */
- NFSERR_XDEV = 18, /* v3 */
- NFSERR_NODEV = 19, /* v2 v3 */
- NFSERR_NOTDIR = 20, /* v2 v3 */
- NFSERR_ISDIR = 21, /* v2 v3 */
- NFSERR_INVAL = 22, /* v2 v3 that Sun forgot */
- NFSERR_FBIG = 27, /* v2 v3 */
- NFSERR_NOSPC = 28, /* v2 v3 */
- NFSERR_ROFS = 30, /* v2 v3 */
- NFSERR_MLINK = 31, /* v3 */
- NFSERR_OPNOTSUPP = 45, /* v2 v3 */
- NFSERR_NAMETOOLONG = 63, /* v2 v3 */
- NFSERR_NOTEMPTY = 66, /* v2 v3 */
- NFSERR_DQUOT = 69, /* v2 v3 */
- NFSERR_STALE = 70, /* v2 v3 */
- NFSERR_REMOTE = 71, /* v2 v3 */
- NFSERR_WFLUSH = 99, /* v2 */
- NFSERR_BADHANDLE = 10001, /* v3 */
- NFSERR_NOT_SYNC = 10002, /* v3 */
- NFSERR_BAD_COOKIE = 10003, /* v3 */
- NFSERR_NOTSUPP = 10004, /* v3 */
- NFSERR_TOOSMALL = 10005, /* v3 */
- NFSERR_SERVERFAULT = 10006, /* v3 */
- NFSERR_BADTYPE = 10007, /* v3 */
- NFSERR_JUKEBOX = 10008 /* v3 */
-};
-
-#define NFS_PROGRAM 100003
-
-
-
-#ifndef NFS_FHSIZE
-static const int NFS_FHSIZE = 32;
-#endif
-#ifndef NFS_PORT
-static const int NFS_PORT = 2049;
-#endif
-
-/* Disable the nls stuff */
-# undef bindtextdomain
-# define bindtextdomain(Domain, Directory) /* empty */
-# undef textdomain
-# define textdomain(Domain) /* empty */
-# define _(Text) (Text)
-# define N_(Text) (Text)
-
-static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */
-static const int MS_RDONLY = 1; /* Mount read-only */
-static const int MS_NOSUID = 2; /* Ignore suid and sgid bits */
-static const int MS_NODEV = 4; /* Disallow access to device special files */
-static const int MS_NOEXEC = 8; /* Disallow program execution */
-static const int MS_SYNCHRONOUS = 16; /* Writes are synced at once */
-static const int MS_REMOUNT = 32; /* Alter flags of a mounted FS */
-static const int MS_MANDLOCK = 64; /* Allow mandatory locks on an FS */
-static const int S_QUOTA = 128; /* Quota initialized for file/directory/symlink */
-static const int S_APPEND = 256; /* Append-only file */
-static const int S_IMMUTABLE = 512; /* Immutable file */
-static const int MS_NOATIME = 1024; /* Do not update access times. */
-static const int MS_NODIRATIME = 2048; /* Do not update directory access times */
-
-
-/*
- * 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).
- */
-
-/* NOTE: Do not make this into a 'static const int' because the pre-processor
- * needs to test this value in some #if statements. */
-#define NFS_MOUNT_VERSION 4
-
-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 */
-
-static const int NFS_MOUNT_SOFT = 0x0001; /* 1 */
-static const int NFS_MOUNT_INTR = 0x0002; /* 1 */
-static const int NFS_MOUNT_SECURE = 0x0004; /* 1 */
-static const int NFS_MOUNT_POSIX = 0x0008; /* 1 */
-static const int NFS_MOUNT_NOCTO = 0x0010; /* 1 */
-static const int NFS_MOUNT_NOAC = 0x0020; /* 1 */
-static const int NFS_MOUNT_TCP = 0x0040; /* 2 */
-static const int NFS_MOUNT_VER3 = 0x0080; /* 3 */
-static const int NFS_MOUNT_KERBEROS = 0x0100; /* 3 */
-static const int NFS_MOUNT_NONLM = 0x0200; /* 3 */
-
-
-#define UTIL_LINUX_VERSION "2.10m"
-#define util_linux_version "util-linux-2.10m"
-
-#define HAVE_inet_aton
-#define HAVE_scsi_h
-#define HAVE_blkpg_h
-#define HAVE_kd_h
-#define HAVE_termcap
-#define HAVE_locale_h
-#define HAVE_libintl_h
-#define ENABLE_NLS
-#define HAVE_langinfo_h
-#define HAVE_progname
-#define HAVE_openpty
-#define HAVE_nanosleep
-#define HAVE_personality
-#define HAVE_tm_gmtoff
-
-static char *nfs_strerror(int status);
-
-#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
-#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
-
-static const int EX_FAIL = 32; /* mount failure */
-static const int EX_BG = 256; /* retry in background (internal only) */
-
-
-/*
- * nfs_mount_version according to the sources seen at compile time.
- */
-static int nfs_mount_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)
-{
- static int kernel_version = 0;
-
- if (kernel_version)
- return;
-
- nfs_mount_version = NFS_MOUNT_VERSION; /* default */
-
- kernel_version = get_kernel_revision();
- if (kernel_version) {
- if (kernel_version < MAKE_VERSION(2,1,32))
- nfs_mount_version = 1;
- else if (kernel_version < MAKE_VERSION(2,2,18) ||
- (kernel_version >= MAKE_VERSION(2,3,0) &&
- kernel_version < MAKE_VERSION(2,3,99)))
- nfs_mount_version = 3;
- else
- nfs_mount_version = 4; /* since 2.3.99pre4 */
- }
- if (nfs_mount_version > NFS_MOUNT_VERSION)
- nfs_mount_version = NFS_MOUNT_VERSION;
-}
-
-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;
-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;
-}
-
-int nfsmount(const char *spec, const char *node, int *flags,
- char **extra_opts, char **mount_opts, int running_bg)
-{
- static char *prev_bg_host;
- char hostdir[1024];
- CLIENT *mclient;
- char *hostname;
- char *pathname;
- char *old_opts;
- char *mounthost=NULL;
- char new_opts[1024];
- struct timeval total_timeout;
- enum clnt_stat clnt_stat;
- static struct nfs_mount_data data;
- char *opt, *opteq;
- int val;
- struct hostent *hp;
- struct sockaddr_in server_addr;
- struct sockaddr_in mount_server_addr;
- struct pmap* pm_mnt;
- int msock, fsock;
- struct timeval retry_timeout;
- union {
- struct fhstatus nfsv2;
- struct mountres3 nfsv3;
- } status;
- struct stat statbuf;
- 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;
- time_t t;
- time_t prevt;
- time_t timeout;
-
- find_kernel_nfs_mount_version();
-
- retval = EX_FAIL;
- msock = fsock = -1;
- mclient = NULL;
- if (strlen(spec) >= sizeof(hostdir)) {
- bb_error_msg("excessively long host:dir argument");
- goto fail;
- }
- strcpy(hostdir, spec);
- if ((s = strchr(hostdir, ':'))) {
- hostname = hostdir;
- pathname = s + 1;
- *s = '\0';
- /* Ignore all but first hostname in replicated mounts
- until they can be fully supported. (mack@sgi.com) */
- if ((s = strchr(hostdir, ','))) {
- *s = '\0';
- bb_error_msg("warning: multiple hostnames not supported");
- }
- } else {
- bb_error_msg("directory to mount not in host:dir format");
- goto fail;
- }
-
- server_addr.sin_family = AF_INET;
-#ifdef HAVE_inet_aton
- if (!inet_aton(hostname, &server_addr.sin_addr))
-#endif
- {
- if ((hp = gethostbyname(hostname)) == NULL) {
- bb_herror_msg("%s", hostname);
- 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);
- }
- 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 */
-
- s = inet_ntoa(server_addr.sin_addr);
- old_opts = *extra_opts;
- if (!old_opts)
- old_opts = "";
- if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
- bb_error_msg("excessively long option argument");
- goto fail;
- }
- sprintf(new_opts, "%s%saddr=%s",
- old_opts, *old_opts ? "," : "", s);
- *extra_opts = bb_xstrdup(new_opts);
-
- /* 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;
-#if NFS_MOUNT_VERSION >= 2
- data.namlen = NAME_MAX;
-#endif
-
- 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 = NFS_PROGRAM;
- nfsvers = 0;
-
- /* parse options */
-
- for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
- if ((opteq = strchr(opt, '='))) {
- val = atoi(opteq + 1);
- *opteq = '\0';
- if (!strcmp(opt, "rsize"))
- data.rsize = val;
- else if (!strcmp(opt, "wsize"))
- data.wsize = val;
- else if (!strcmp(opt, "timeo"))
- data.timeo = val;
- else if (!strcmp(opt, "retrans"))
- data.retrans = val;
- else if (!strcmp(opt, "acregmin"))
- data.acregmin = val;
- else if (!strcmp(opt, "acregmax"))
- data.acregmax = val;
- else if (!strcmp(opt, "acdirmin"))
- data.acdirmin = val;
- else if (!strcmp(opt, "acdirmax"))
- data.acdirmax = val;
- else if (!strcmp(opt, "actimeo")) {
- data.acregmin = val;
- data.acregmax = val;
- data.acdirmin = val;
- data.acdirmax = val;
- }
- else if (!strcmp(opt, "retry"))
- retry = val;
- else if (!strcmp(opt, "port"))
- port = val;
- else if (!strcmp(opt, "mountport"))
- mountport = val;
- else if (!strcmp(opt, "mounthost"))
- mounthost=bb_xstrndup(opteq+1,
- strcspn(opteq+1," \t\n\r,"));
- else if (!strcmp(opt, "mountprog"))
- mountprog = val;
- else if (!strcmp(opt, "mountvers"))
- mountvers = val;
- else if (!strcmp(opt, "nfsprog"))
- nfsprog = val;
- else if (!strcmp(opt, "nfsvers") ||
- !strcmp(opt, "vers"))
- nfsvers = val;
- else if (!strcmp(opt, "proto")) {
- if (!strncmp(opteq+1, "tcp", 3))
- tcp = 1;
- else if (!strncmp(opteq+1, "udp", 3))
- tcp = 0;
- else
- printf(_("Warning: Unrecognized proto= option.\n"));
- } else if (!strcmp(opt, "namlen")) {
-#if NFS_MOUNT_VERSION >= 2
- if (nfs_mount_version >= 2)
- data.namlen = val;
- else
-#endif
- printf(_("Warning: Option namlen is not supported.\n"));
- } else if (!strcmp(opt, "addr"))
- /* ignore */;
- else {
- printf(_("unknown nfs mount parameter: "
- "%s=%d\n"), opt, val);
- goto fail;
- }
- }
- else {
- val = 1;
- if (!strncmp(opt, "no", 2)) {
- val = 0;
- opt += 2;
- }
- if (!strcmp(opt, "bg"))
- bg = val;
- else if (!strcmp(opt, "fg"))
- bg = !val;
- else if (!strcmp(opt, "soft"))
- soft = val;
- else if (!strcmp(opt, "hard"))
- soft = !val;
- else if (!strcmp(opt, "intr"))
- intr = val;
- else if (!strcmp(opt, "posix"))
- posix = val;
- else if (!strcmp(opt, "cto"))
- nocto = !val;
- else if (!strcmp(opt, "ac"))
- noac = !val;
- else if (!strcmp(opt, "tcp"))
- tcp = val;
- else if (!strcmp(opt, "udp"))
- tcp = !val;
- else if (!strcmp(opt, "lock")) {
- if (nfs_mount_version >= 3)
- nolock = !val;
- else
- printf(_("Warning: option nolock is not supported.\n"));
- } else {
- printf(_("unknown nfs mount option: "
- "%s%s\n"), 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
- if (nfs_mount_version >= 2)
- data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
-#endif
-#if NFS_MOUNT_VERSION >= 3
- if (nfs_mount_version >= 3)
- data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
-#endif
- if (nfsvers > MAX_NFSPROT) {
- bb_error_msg("NFSv%d not supported!", nfsvers);
- return 0;
- }
- if (mountvers > MAX_NFSPROT) {
- bb_error_msg("NFSv%d not supported!", nfsvers);
- return 0;
- }
- 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;
-
-#ifdef NFS_MOUNT_DEBUG
- printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
- data.rsize, data.wsize, data.timeo, data.retrans);
- printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
- data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
- printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
- port, bg, retry, data.flags);
- printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
- mountprog, mountvers, nfsprog, nfsvers);
- printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
- (data.flags & NFS_MOUNT_SOFT) != 0,
- (data.flags & NFS_MOUNT_INTR) != 0,
- (data.flags & NFS_MOUNT_POSIX) != 0,
- (data.flags & NFS_MOUNT_NOCTO) != 0,
- (data.flags & NFS_MOUNT_NOAC) != 0);
-#if NFS_MOUNT_VERSION >= 2
- printf("tcp = %d\n",
- (data.flags & NFS_MOUNT_TCP) != 0);
-#endif
-#endif
-
- data.version = nfs_mount_version;
- *mount_opts = (char *) &data;
-
- if (*flags & MS_REMOUNT)
- return 0;
-
- /*
- * 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 && !running_bg &&
- prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
- if (retry > 0)
- retval = EX_BG;
- return retval;
- }
-
- /* create mount deamon 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 {
- if ((hp = gethostbyname(mounthost)) == 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. On the first
- * call, "running_bg" is 0. When the mount times out, and the
- * "bg" option is set, the exit status EX_BG will be returned.
- * For a backgrounded mount, there will be a second call by the
- * child process with "running_bg" set to 1.
- *
- * 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.
- *
- * Only the first error message will be displayed.
- */
- 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;
- val = 1;
- for (;;) {
- if (bg && stat(node, &statbuf) == -1) {
- if (running_bg) {
- sleep(val); /* 1, 2, 4, 8, 16, 30, ... */
- val *= 2;
- if (val > 30)
- val = 30;
- }
- } else {
- /* 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);
-
- /* 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) {
- /* 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)
- break; /* we're done */
- if (errno != ECONNREFUSED) {
- clnt_perror(mclient, "mount");
- goto fail; /* don't retry */
- }
- if (!running_bg && prevt == 0)
- clnt_perror(mclient, "mount");
- auth_destroy(mclient->cl_auth);
- clnt_destroy(mclient);
- mclient = 0;
- close(msock);
- } else {
- if (!running_bg && prevt == 0)
- clnt_pcreateerror("mount");
- }
- prevt = t;
- }
- if (!bg)
- goto fail;
- if (!running_bg) {
- prev_bg_host = bb_xstrdup(hostname);
- if (retry > 0)
- retval = EX_BG;
- goto fail;
- }
- t = time(NULL);
- if (t >= timeout)
- goto fail;
- }
- nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
-
- 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);
-#if NFS_MOUNT_VERSION >= 4
- data.root.size = NFS_FHSIZE;
- memcpy(data.old_root.data,
- (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
- NFS_FHSIZE);
-#endif
- } else {
-#if NFS_MOUNT_VERSION >= 4
- 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;
-#endif
- }
-
- /* create nfs socket for kernel */
-
- if (tcp) {
- if (nfs_mount_version < 3) {
- printf(_("NFS over TCP is not supported.\n"));
- goto fail;
- }
- fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- } else
- fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (fsock < 0) {
- perror(_("nfs socket"));
- goto fail;
- }
- if (bindresvport(fsock, 0) < 0) {
- perror(_("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;
-#ifdef NFS_MOUNT_DEBUG
- else
- printf(_("used portmapper to find NFS port\n"));
-#endif
- }
-#ifdef NFS_MOUNT_DEBUG
- printf(_("using port %d for nfs deamon\n"), port);
-#endif
- server_addr.sin_port = htons(port);
- /*
- * connect() the socket for kernels 1.3.10 and below only,
- * to avoid problems with multihomed hosts.
- * --Swen
- */
- if (get_kernel_revision() <= 66314
- && connect(fsock, (struct sockaddr *) &server_addr,
- sizeof (server_addr)) < 0) {
- perror(_("nfs connect"));
- goto fail;
- }
-
- /* 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);
- return 0;
-
- /* abort */
-
-fail:
- if (msock != -1) {
- if (mclient) {
- auth_destroy(mclient->cl_auth);
- clnt_destroy(mclient);
- }
- close(msock);
- }
- if (fsock != -1)
- close(fsock);
- return retval;
-}
-
-/*
- * 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
-
-static struct {
- enum nfs_stat stat;
- int errnum;
-} nfs_errtbl[] = {
- { NFS_OK, 0 },
- { NFSERR_PERM, EPERM },
- { NFSERR_NOENT, ENOENT },
- { NFSERR_IO, EIO },
- { NFSERR_NXIO, ENXIO },
- { NFSERR_ACCES, EACCES },
- { NFSERR_EXIST, EEXIST },
- { NFSERR_NODEV, ENODEV },
- { NFSERR_NOTDIR, ENOTDIR },
- { NFSERR_ISDIR, EISDIR },
-#ifdef NFSERR_INVAL
- { NFSERR_INVAL, EINVAL }, /* that Sun forgot */
-#endif
- { NFSERR_FBIG, EFBIG },
- { NFSERR_NOSPC, ENOSPC },
- { NFSERR_ROFS, EROFS },
- { NFSERR_NAMETOOLONG, ENAMETOOLONG },
- { NFSERR_NOTEMPTY, ENOTEMPTY },
- { NFSERR_DQUOT, EDQUOT },
- { NFSERR_STALE, ESTALE },
-#ifdef EWFLUSH
- { NFSERR_WFLUSH, EWFLUSH },
-#endif
- /* Throw in some NFSv3 values for even more fun (HP returns these) */
- { 71, EREMOTE },
-
- { -1, EIO }
-};
-
-static char *nfs_strerror(int status)
-{
- int i;
- static char buf[256];
-
- 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)
-{
- //register int32_t *buf;
-
- if (!xdr_opaque (xdrs, objp, FHSIZE))
- return FALSE;
- return TRUE;
-}
-
-bool_t
-xdr_fhstatus (XDR *xdrs, fhstatus *objp)
-{
- //register int32_t *buf;
-
- 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;
-}
-
-bool_t
-xdr_dirpath (XDR *xdrs, dirpath *objp)
-{
- //register int32_t *buf;
-
- if (!xdr_string (xdrs, objp, MNTPATHLEN))
- return FALSE;
- return TRUE;
-}
-
-bool_t
-xdr_fhandle3 (XDR *xdrs, fhandle3 *objp)
-{
- //register int32_t *buf;
-
- if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3))
- return FALSE;
- return TRUE;
-}
-
-bool_t
-xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp)
-{
- //register int32_t *buf;
-
- if (!xdr_fhandle3 (xdrs, &objp->fhandle))
- return FALSE;
- if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (u_int *) &objp->auth_flavours.auth_flavours_len, ~0,
- sizeof (int), (xdrproc_t) xdr_int))
- return FALSE;
- return TRUE;
-}
-
-bool_t
-xdr_mountstat3 (XDR *xdrs, mountstat3 *objp)
-{
- //register int32_t *buf;
-
- if (!xdr_enum (xdrs, (enum_t *) objp))
- return FALSE;
- return TRUE;
-}
-
-bool_t
-xdr_mountres3 (XDR *xdrs, mountres3 *objp)
-{
- //register int32_t *buf;
-
- 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;
-}
-
diff --git a/release/src/router/busybox/util-linux/nfsmount.h b/release/src/router/busybox/util-linux/nfsmount.h
deleted file mode 100644
index b3d5a51e..00000000
--- a/release/src/router/busybox/util-linux/nfsmount.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * This file was originally generated using rpcgen.
- * But now we edit it by hand as needed to make it
- * shut up...
- */
-
-#ifndef _NFSMOUNT_H_RPCGEN
-#define _NFSMOUNT_H_RPCGEN
-
-#include <rpc/rpc.h>
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
- * unrestricted use provided that this legend is included on all tape
- * media and as a part of the software program in whole or part. Users
- * may copy or modify Sun RPC without charge, but are not authorized
- * to license or distribute it to anyone else except as part of a product or
- * program developed by the user or with the express written consent of
- * Sun Microsystems, Inc.
- *
- * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
- * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
- *
- * Sun RPC is provided with no support and without any obligation on the
- * part of Sun Microsystems, Inc. to assist in its use, correction,
- * modification or enhancement.
- *
- * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
- * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
- * OR ANY PART THEREOF.
- *
- * In no event will Sun Microsystems, Inc. be liable for any lost revenue
- * or profits or other special, indirect and consequential damages, even if
- * Sun has been advised of the possibility of such damages.
- *
- * Sun Microsystems, Inc.
- * 2550 Garcia Avenue
- * Mountain View, California 94043
- */
-/*
- * Copyright (c) 1985, 1990 by Sun Microsystems, Inc.
- */
-
-/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */
-#ifndef _rpcsvc_mount_h
-#define _rpcsvc_mount_h
-#include <asm/types.h>
-#define MOUNTPORT 635
-#define MNTPATHLEN 1024
-#define MNTNAMLEN 255
-#define FHSIZE 32
-#define FHSIZE3 64
-
-typedef char fhandle[FHSIZE];
-
-typedef struct {
- u_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 {
- u_int fhs_status;
- union {
- fhandle fhs_fhandle;
- } fhstatus_u;
-};
-typedef struct fhstatus fhstatus;
-
-struct mountres3_ok {
- fhandle3 fhandle;
- struct {
- u_int auth_flavours_len;
- int *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;
- u_char pc_vdisable;
- char pc_xxx;
- short pc_mask[2];
-};
-typedef struct ppathcnf ppathcnf;
-#endif /*!_rpcsvc_mount_h*/
-
-#define MOUNTPROG 100005
-#define MOUNTVERS 1
-
-#define MOUNTPROC_NULL 0
-extern void * mountproc_null_1(void *, CLIENT *);
-extern void * mountproc_null_1_svc(void *, struct svc_req *);
-#define MOUNTPROC_MNT 1
-extern fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
-extern fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
-#define MOUNTPROC_DUMP 2
-extern mountlist * mountproc_dump_1(void *, CLIENT *);
-extern mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
-#define MOUNTPROC_UMNT 3
-extern void * mountproc_umnt_1(dirpath *, CLIENT *);
-extern void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
-#define MOUNTPROC_UMNTALL 4
-extern void * mountproc_umntall_1(void *, CLIENT *);
-extern void * mountproc_umntall_1_svc(void *, struct svc_req *);
-#define MOUNTPROC_EXPORT 5
-extern exports * mountproc_export_1(void *, CLIENT *);
-extern exports * mountproc_export_1_svc(void *, struct svc_req *);
-#define MOUNTPROC_EXPORTALL 6
-extern exports * mountproc_exportall_1(void *, CLIENT *);
-extern exports * mountproc_exportall_1_svc(void *, struct svc_req *);
-extern int mountprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
-
-#define MOUNTVERS_POSIX 2
-
-extern void * mountproc_null_2(void *, CLIENT *);
-extern void * mountproc_null_2_svc(void *, struct svc_req *);
-extern fhstatus * mountproc_mnt_2(dirpath *, CLIENT *);
-extern fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *);
-extern mountlist * mountproc_dump_2(void *, CLIENT *);
-extern mountlist * mountproc_dump_2_svc(void *, struct svc_req *);
-extern void * mountproc_umnt_2(dirpath *, CLIENT *);
-extern void * mountproc_umnt_2_svc(dirpath *, struct svc_req *);
-extern void * mountproc_umntall_2(void *, CLIENT *);
-extern void * mountproc_umntall_2_svc(void *, struct svc_req *);
-extern exports * mountproc_export_2(void *, CLIENT *);
-extern exports * mountproc_export_2_svc(void *, struct svc_req *);
-extern exports * mountproc_exportall_2(void *, CLIENT *);
-extern exports * mountproc_exportall_2_svc(void *, struct svc_req *);
-#define MOUNTPROC_PATHCONF 7
-extern ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *);
-extern ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *);
-extern int mountprog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
-
-#define MOUNT_V3 3
-
-#define MOUNTPROC3_NULL 0
-extern void * mountproc3_null_3(void *, CLIENT *);
-extern void * mountproc3_null_3_svc(void *, struct svc_req *);
-#define MOUNTPROC3_MNT 1
-extern mountres3 * mountproc3_mnt_3(dirpath *, CLIENT *);
-extern mountres3 * mountproc3_mnt_3_svc(dirpath *, struct svc_req *);
-#define MOUNTPROC3_DUMP 2
-extern mountlist * mountproc3_dump_3(void *, CLIENT *);
-extern mountlist * mountproc3_dump_3_svc(void *, struct svc_req *);
-#define MOUNTPROC3_UMNT 3
-extern void * mountproc3_umnt_3(dirpath *, CLIENT *);
-extern void * mountproc3_umnt_3_svc(dirpath *, struct svc_req *);
-#define MOUNTPROC3_UMNTALL 4
-extern void * mountproc3_umntall_3(void *, CLIENT *);
-extern void * mountproc3_umntall_3_svc(void *, struct svc_req *);
-#define MOUNTPROC3_EXPORT 5
-extern exports * mountproc3_export_3(void *, CLIENT *);
-extern exports * mountproc3_export_3_svc(void *, struct svc_req *);
-extern int mountprog_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
-
-/* the xdr functions */
-
-static bool_t xdr_fhandle (XDR *, fhandle);
-extern bool_t xdr_fhandle3 (XDR *, fhandle3*);
-extern bool_t xdr_mountstat3 (XDR *, mountstat3*);
-extern bool_t xdr_fhstatus (XDR *, fhstatus*);
-extern bool_t xdr_mountres3_ok (XDR *, mountres3_ok*);
-extern bool_t xdr_mountres3 (XDR *, mountres3*);
-extern bool_t xdr_dirpath (XDR *, dirpath*);
-extern bool_t xdr_name (XDR *, name*);
-extern bool_t xdr_mountlist (XDR *, mountlist*);
-extern bool_t xdr_mountbody (XDR *, mountbody*);
-extern bool_t xdr_groups (XDR *, groups*);
-extern bool_t xdr_groupnode (XDR *, groupnode*);
-extern bool_t xdr_exports (XDR *, exports*);
-extern bool_t xdr_exportnode (XDR *, exportnode*);
-extern bool_t xdr_ppathcnf (XDR *, ppathcnf*);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !_NFSMOUNT_H_RPCGEN */
diff --git a/release/src/router/busybox/util-linux/pivot_root.c b/release/src/router/busybox/util-linux/pivot_root.c
index 39453a26..28af00cc 100644
--- a/release/src/router/busybox/util-linux/pivot_root.c
+++ b/release/src/router/busybox/util-linux/pivot_root.c
@@ -4,32 +4,24 @@
*
* busyboxed by Evin Robertson
* pivot_root syscall stubbed by Erik Andersen, so it will compile
- * regardless of the kernel being used.
+ * regardless of the kernel being used.
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include "busybox.h"
+#include "libbb.h"
extern int pivot_root(const char * new_root,const char * put_old);
+int pivot_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int pivot_root_main(int argc, char **argv)
{
- if (argc != 3)
- bb_show_usage();
-
- if (pivot_root(argv[1],argv[2]) < 0)
- bb_perror_msg_and_die("pivot_root");
+ if (argc != 3)
+ bb_show_usage();
- return EXIT_SUCCESS;
+ if (pivot_root(argv[1], argv[2]) < 0) {
+ /* prints "pivot_root: <strerror text>" */
+ bb_perror_nomsg_and_die();
+ }
+ return EXIT_SUCCESS;
}
-
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/util-linux/rdate.c b/release/src/router/busybox/util-linux/rdate.c
index a5699ebf..0880edff 100644
--- a/release/src/router/busybox/util-linux/rdate.c
+++ b/release/src/router/busybox/util-linux/rdate.c
@@ -5,99 +5,66 @@
*
* by Sterling Huxley <sterling@europa.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPL v2 or later, see file License for details.
*/
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <getopt.h>
-#include <string.h>
-#include <time.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
+#include "libbb.h"
+enum { RFC_868_BIAS = 2208988800UL };
-static const int RFC_868_BIAS = 2208988800UL;
+static void socket_timeout(int sig UNUSED_PARAM)
+{
+ bb_error_msg_and_die("timeout connecting to time server");
+}
static time_t askremotedate(const char *host)
{
- unsigned long int nett, localt;
- const char *port="37";
+ uint32_t nett;
int fd;
- if (getservbyname("time", "tcp") != NULL)
- port="time";
+ /* Add a timeout for dead or inaccessible servers */
+ alarm(10);
+ signal(SIGALRM, socket_timeout);
- fd = xconnect(host, port);
+ 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
+ * 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
*/
- localt= ntohl(nett) - RFC_868_BIAS;
- return(localt);
+ return ntohl(nett) - RFC_868_BIAS;
}
-int rdate_main(int argc, char **argv)
+int rdate_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int rdate_main(int argc UNUSED_PARAM, char **argv)
{
time_t remote_time;
- int opt;
- int setdate = 1;
- int printdate = 1;
-
- /* Interpret command line args */
- while ((opt = getopt(argc, argv, "sp")) > 0) {
- switch (opt) {
- case 's':
- printdate = 0;
- setdate = 1;
- break;
- case 'p':
- printdate = 1;
- setdate = 0;
- break;
- default:
- bb_show_usage();
- }
- }
+ unsigned long flags;
- if (optind == argc)
- bb_show_usage();
+ opt_complementary = "-1";
+ flags = getopt32(argv, "sp");
remote_time = askremotedate(argv[optind]);
- if (setdate) {
- if (stime(&remote_time) < 0)
- bb_perror_msg_and_die("Could not set time of day");
+ 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 (printdate)
+ if ((flags & 1) == 0)
printf("%s", ctime(&remote_time));
return EXIT_SUCCESS;
diff --git a/release/src/router/busybox/util-linux/rdev.c b/release/src/router/busybox/util-linux/rdev.c
new file mode 100644
index 00000000..33abd39d
--- /dev/null
+++ b/release/src/router/busybox/util-linux/rdev.c
@@ -0,0 +1,24 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * rdev - print device node associated with a filesystem
+ *
+ * Copyright (c) 2008 Nuovation System Designs, LLC
+ * Grant Erickson <gerickson@nuovations.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ *
+ */
+
+#include "libbb.h"
+
+int rdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int rdev_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
+{
+ char const * const root_device = find_block_device("/");
+
+ if (root_device != NULL) {
+ printf("%s /\n", root_device);
+ return EXIT_SUCCESS;
+ }
+ return EXIT_FAILURE;
+}
diff --git a/release/src/router/busybox/util-linux/readprofile.c b/release/src/router/busybox/util-linux/readprofile.c
new file mode 100644
index 00000000..1f5ba2ec
--- /dev/null
+++ b/release/src/router/busybox/util-linux/readprofile.c
@@ -0,0 +1,247 @@
+/* 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 Mickiewicz <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 "libbb.h"
+#include <sys/utsname.h>
+
+#define S_LEN 128
+
+/* These are the defaults */
+static const char defaultmap[] ALIGN1 = "/boot/System.map";
+static const char defaultpro[] ALIGN1 = "/proc/profile";
+
+int readprofile_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int readprofile_main(int argc UNUSED_PARAM, char **argv)
+{
+ FILE *map;
+ const char *mapFile, *proFile;
+ 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 maplineno = 1;
+ int header_printed;
+ int multiplier = 0;
+ unsigned opt;
+ enum {
+ OPT_M = (1 << 0),
+ OPT_m = (1 << 1),
+ OPT_p = (1 << 2),
+ OPT_n = (1 << 3),
+ OPT_a = (1 << 4),
+ OPT_b = (1 << 5),
+ OPT_s = (1 << 6),
+ OPT_i = (1 << 7),
+ OPT_r = (1 << 8),
+ OPT_v = (1 << 9),
+ };
+#define optMult (opt & OPT_M)
+#define optNative (opt & OPT_n)
+#define optAll (opt & OPT_a)
+#define optBins (opt & OPT_b)
+#define optSub (opt & OPT_s)
+#define optInfo (opt & OPT_i)
+#define optReset (opt & OPT_r)
+#define optVerbose (opt & OPT_v)
+
+#define next (current^1)
+
+ proFile = defaultpro;
+ mapFile = defaultmap;
+
+ opt_complementary = "M+"; /* -M N */
+ opt = getopt32(argv, "M:m:p:nabsirv", &multiplier, &mapFile, &proFile);
+
+ if (opt & (OPT_M|OPT_r)) { /* mult or reset, or both */
+ int fd, to_write;
+
+ /*
+ * When writing the multiplier, if the length of the write is
+ * not sizeof(int), the multiplier is not changed
+ */
+ to_write = sizeof(int);
+ if (!optMult)
+ to_write = 1; /* sth different from sizeof(int) */
+
+ fd = xopen(defaultpro, O_WRONLY);
+ xwrite(fd, &multiplier, to_write);
+ close(fd);
+ return EXIT_SUCCESS;
+ }
+
+ /*
+ * Use an fd for the profiling buffer, to skip stdio overhead
+ */
+ len = MAXINT(ssize_t);
+ buf = xmalloc_xopen_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_for_read(mapFile);
+
+ 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/release/src/router/busybox/util-linux/rtcwake.c b/release/src/router/busybox/util-linux/rtcwake.c
new file mode 100644
index 00000000..9a73ba29
--- /dev/null
+++ b/release/src/router/busybox/util-linux/rtcwake.c
@@ -0,0 +1,201 @@
+/*
+ * rtcwake -- enter a system sleep state until specified wakeup time.
+ *
+ * This version was taken from util-linux and scrubbed down for busybox.
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ *
+ * This uses cross-platform Linux interfaces to enter a system sleep state,
+ * and leave it no later than a specified time. It uses any RTC framework
+ * driver that supports standard driver model wakeup flags.
+ *
+ * This is normally used like the old "apmsleep" utility, to wake from a
+ * suspend state like ACPI S1 (standby) or S3 (suspend-to-RAM). Most
+ * platforms can implement those without analogues of BIOS, APM, or ACPI.
+ *
+ * On some systems, this can also be used like "nvram-wakeup", waking
+ * from states like ACPI S4 (suspend to disk). Not all systems have
+ * persistent media that are appropriate for such suspend modes.
+ *
+ * The best way to set the system's RTC is so that it holds the current
+ * time in UTC. Use the "-l" flag to tell this program that the system
+ * RTC uses a local timezone instead (maybe you dual-boot MS-Windows).
+ * That flag should not be needed on systems with adjtime support.
+ */
+
+#include "libbb.h"
+#include "rtc_.h"
+
+#define SYS_RTC_PATH "/sys/class/rtc/%s/device/power/wakeup"
+#define SYS_POWER_PATH "/sys/power/state"
+#define DEFAULT_MODE "standby"
+
+static time_t rtc_time;
+
+static bool may_wakeup(const char *rtcname)
+{
+ ssize_t ret;
+ char buf[128];
+
+ /* strip the '/dev/' from the rtcname here */
+ if (!strncmp(rtcname, "/dev/", 5))
+ rtcname += 5;
+
+ snprintf(buf, sizeof(buf), SYS_RTC_PATH, rtcname);
+ ret = open_read_close(buf, buf, sizeof(buf));
+ if (ret < 0)
+ return false;
+
+ /* wakeup events could be disabled or not supported */
+ return strncmp(buf, "enabled\n", 8) == 0;
+}
+
+static void setup_alarm(int fd, time_t *wakeup)
+{
+ struct tm *tm;
+ struct linux_rtc_wkalrm wake;
+
+ /* The wakeup time is in POSIX time (more or less UTC).
+ * Ideally RTCs use that same time; but PCs can't do that
+ * if they need to boot MS-Windows. Messy...
+ *
+ * When running in utc mode this process's timezone is UTC,
+ * so we'll pass a UTC date to the RTC.
+ *
+ * Else mode is local so the time given to the RTC
+ * will instead use the local time zone.
+ */
+ tm = localtime(wakeup);
+
+ wake.time.tm_sec = tm->tm_sec;
+ wake.time.tm_min = tm->tm_min;
+ wake.time.tm_hour = tm->tm_hour;
+ wake.time.tm_mday = tm->tm_mday;
+ wake.time.tm_mon = tm->tm_mon;
+ wake.time.tm_year = tm->tm_year;
+ /* wday, yday, and isdst fields are unused by Linux */
+ wake.time.tm_wday = -1;
+ wake.time.tm_yday = -1;
+ wake.time.tm_isdst = -1;
+
+ /* many rtc alarms only support up to 24 hours from 'now',
+ * so use the "more than 24 hours" request only if we must
+ */
+ if ((rtc_time + (24 * 60 * 60)) > *wakeup) {
+ xioctl(fd, RTC_ALM_SET, &wake.time);
+ xioctl(fd, RTC_AIE_ON, 0);
+ } else {
+ /* avoid an extra AIE_ON call */
+ wake.enabled = 1;
+ xioctl(fd, RTC_WKALM_SET, &wake);
+ }
+}
+
+#define RTCWAKE_OPT_AUTO 0x01
+#define RTCWAKE_OPT_LOCAL 0x02
+#define RTCWAKE_OPT_UTC 0x04
+#define RTCWAKE_OPT_DEVICE 0x08
+#define RTCWAKE_OPT_SUSPEND_MODE 0x10
+#define RTCWAKE_OPT_SECONDS 0x20
+#define RTCWAKE_OPT_TIME 0x40
+
+int rtcwake_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int rtcwake_main(int argc UNUSED_PARAM, char **argv)
+{
+ unsigned opt;
+ const char *rtcname = NULL;
+ const char *suspend;
+ const char *opt_seconds;
+ const char *opt_time;
+
+ time_t sys_time;
+ time_t alarm_time = 0;
+ unsigned seconds = 0;
+ int utc = -1;
+ int fd;
+
+#if ENABLE_GETOPT_LONG
+ static const char rtcwake_longopts[] ALIGN1 =
+ "auto\0" No_argument "a"
+ "local\0" No_argument "l"
+ "utc\0" No_argument "u"
+ "device\0" Required_argument "d"
+ "mode\0" Required_argument "m"
+ "seconds\0" Required_argument "s"
+ "time\0" Required_argument "t"
+ ;
+ applet_long_options = rtcwake_longopts;
+#endif
+ opt = getopt32(argv, "alud:m:s:t:", &rtcname, &suspend, &opt_seconds, &opt_time);
+
+ /* this is the default
+ if (opt & RTCWAKE_OPT_AUTO)
+ utc = -1;
+ */
+ if (opt & (RTCWAKE_OPT_UTC | RTCWAKE_OPT_LOCAL))
+ utc = opt & RTCWAKE_OPT_UTC;
+ if (!(opt & RTCWAKE_OPT_SUSPEND_MODE))
+ suspend = DEFAULT_MODE;
+ if (opt & RTCWAKE_OPT_SECONDS)
+ /* alarm time, seconds-to-sleep (relative) */
+ seconds = xatoi(opt_seconds);
+ if (opt & RTCWAKE_OPT_TIME)
+ /* alarm time, time_t (absolute, seconds since 1/1 1970 UTC) */
+ alarm_time = xatoi(opt_time);
+
+ if (!alarm_time && !seconds)
+ bb_error_msg_and_die("must provide wake time");
+
+ if (utc == -1)
+ utc = rtc_adjtime_is_utc();
+
+ /* the rtcname is relative to /dev */
+ xchdir("/dev");
+
+ /* this RTC must exist and (if we'll sleep) be wakeup-enabled */
+ fd = rtc_xopen(&rtcname, O_RDONLY);
+
+ if (strcmp(suspend, "on") && !may_wakeup(rtcname))
+ bb_error_msg_and_die("%s not enabled for wakeup events", rtcname);
+
+ /* relative or absolute alarm time, normalized to time_t */
+ sys_time = time(NULL);
+ if (sys_time == (time_t)-1)
+ bb_perror_msg_and_die("read system time");
+ rtc_time = rtc_read_time(fd, utc);
+
+ if (alarm_time) {
+ if (alarm_time < sys_time)
+ bb_error_msg_and_die("time doesn't go backward to %s", ctime(&alarm_time));
+ alarm_time += sys_time - rtc_time;
+ } else
+ alarm_time = rtc_time + seconds + 1;
+ setup_alarm(fd, &alarm_time);
+
+ sync();
+ printf("wakeup from \"%s\" at %s", suspend, ctime(&alarm_time));
+ fflush(stdout);
+ usleep(10 * 1000);
+
+ if (strcmp(suspend, "on"))
+ xopen_xwrite_close(SYS_POWER_PATH, suspend);
+ else {
+ /* "fake" suspend ... we'll do the delay ourselves */
+ unsigned long data;
+
+ do {
+ ssize_t ret = safe_read(fd, &data, sizeof(data));
+ if (ret < 0) {
+ bb_perror_msg("rtc read");
+ break;
+ }
+ } while (!(data & RTC_AF));
+ }
+
+ xioctl(fd, RTC_AIE_OFF, 0);
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(fd);
+
+ return EXIT_SUCCESS;
+}
diff --git a/release/src/router/busybox/util-linux/script.c b/release/src/router/busybox/util-linux/script.c
new file mode 100644
index 00000000..a9f24b10
--- /dev/null
+++ b/release/src/router/busybox/util-linux/script.c
@@ -0,0 +1,186 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * script implementation for busybox
+ *
+ * pascal.bellard@ads-lu.com
+ *
+ * Based on code from util-linux v 2.12r
+ * Copyright (c) 1980
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Licensed under GPLv2 or later, see file License in this tarball for details.
+ */
+
+#include "libbb.h"
+
+static smallint fd_count = 2;
+
+static void handle_sigchld(int sig UNUSED_PARAM)
+{
+ fd_count = 0;
+}
+
+int script_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int script_main(int argc UNUSED_PARAM, char **argv)
+{
+ int opt;
+ int mode;
+ int child_pid;
+ int attr_ok; /* NB: 0: ok */
+ int winsz_ok;
+ int pty;
+ char pty_line[GETPTY_BUFSIZE];
+ struct termios tt, rtt;
+ struct winsize win;
+ const char *fname = "typescript";
+ const char *shell;
+ char shell_opt[] = "-i";
+ char *shell_arg = NULL;
+
+#if ENABLE_GETOPT_LONG
+ static const char getopt_longopts[] ALIGN1 =
+ "append\0" No_argument "a"
+ "command\0" Required_argument "c"
+ "flush\0" No_argument "f"
+ "quiet\0" No_argument "q"
+ ;
+
+ applet_long_options = getopt_longopts;
+#endif
+ opt_complementary = "?1"; /* max one arg */
+ opt = getopt32(argv, "ac:fq", &shell_arg);
+ //argc -= optind;
+ argv += optind;
+ if (argv[0]) {
+ fname = argv[0];
+ }
+ mode = O_CREAT|O_TRUNC|O_WRONLY;
+ if (opt & 1) {
+ mode = O_CREAT|O_APPEND|O_WRONLY;
+ }
+ if (opt & 2) {
+ shell_opt[1] = 'c';
+ }
+ if (!(opt & 8)) { /* not -q */
+ printf("Script started, file is %s\n", fname);
+ }
+ shell = getenv("SHELL");
+ if (shell == NULL) {
+ shell = DEFAULT_SHELL;
+ }
+
+ pty = xgetpty(pty_line);
+
+ /* get current stdin's tty params */
+ attr_ok = tcgetattr(0, &tt);
+ winsz_ok = ioctl(0, TIOCGWINSZ, (char *)&win);
+
+ rtt = tt;
+ cfmakeraw(&rtt);
+ rtt.c_lflag &= ~ECHO;
+ tcsetattr(0, TCSAFLUSH, &rtt);
+
+ /* "script" from util-linux exits when child exits,
+ * we wouldn't wait for EOF from slave pty
+ * (output may be produced by grandchildren of child) */
+ signal(SIGCHLD, handle_sigchld);
+
+ /* TODO: SIGWINCH? pass window size changes down to slave? */
+
+ child_pid = vfork();
+ if (child_pid < 0) {
+ bb_perror_msg_and_die("vfork");
+ }
+
+ if (child_pid) {
+ /* parent */
+#define buf bb_common_bufsiz1
+ struct pollfd pfd[2];
+ int outfd, count, loop;
+
+ outfd = xopen(fname, mode);
+ pfd[0].fd = pty;
+ pfd[0].events = POLLIN;
+ pfd[1].fd = 0;
+ pfd[1].events = POLLIN;
+ ndelay_on(pty); /* this descriptor is not shared, can do this */
+ /* ndelay_on(0); - NO, stdin can be shared! Pity :( */
+
+ /* copy stdin to pty master input,
+ * copy pty master output to stdout and file */
+ /* TODO: don't use full_write's, use proper write buffering */
+ while (fd_count) {
+ /* not safe_poll! we want SIGCHLD to EINTR poll */
+ if (poll(pfd, fd_count, -1) < 0 && errno != EINTR) {
+ /* If child exits too quickly, we may get EIO:
+ * for example, try "script -c true" */
+ break;
+ }
+ if (pfd[0].revents) {
+ errno = 0;
+ count = safe_read(pty, buf, sizeof(buf));
+ if (count <= 0 && errno != EAGAIN) {
+ /* err/eof from pty: exit */
+ goto restore;
+ }
+ if (count > 0) {
+ full_write(STDOUT_FILENO, buf, count);
+ full_write(outfd, buf, count);
+ if (opt & 4) { /* -f */
+ fsync(outfd);
+ }
+ }
+ }
+ if (pfd[1].revents) {
+ count = safe_read(STDIN_FILENO, buf, sizeof(buf));
+ if (count <= 0) {
+ /* err/eof from stdin: don't read stdin anymore */
+ pfd[1].revents = 0;
+ fd_count--;
+ } else {
+ full_write(pty, buf, count);
+ }
+ }
+ }
+ /* If loop was exited because SIGCHLD handler set fd_count to 0,
+ * there still can be some buffered output. But not loop forever:
+ * we won't pump orphaned grandchildren's output indefinitely.
+ * Testcase: running this in script:
+ * exec dd if=/dev/zero bs=1M count=1
+ * must have "1+0 records in, 1+0 records out" captured too.
+ * (util-linux's script doesn't do this. buggy :) */
+ loop = 999;
+ /* pty is in O_NONBLOCK mode, we exit as soon as buffer is empty */
+ while (--loop && (count = safe_read(pty, buf, sizeof(buf))) > 0) {
+ full_write(STDOUT_FILENO, buf, count);
+ full_write(outfd, buf, count);
+ }
+ restore:
+ if (attr_ok == 0)
+ tcsetattr(0, TCSAFLUSH, &tt);
+ if (!(opt & 8)) /* not -q */
+ printf("Script done, file is %s\n", fname);
+ return EXIT_SUCCESS;
+ }
+
+ /* child: make pty slave to be input, output, error; run shell */
+ close(pty); /* close pty master */
+ /* open pty slave to fd 0,1,2 */
+ close(0);
+ xopen(pty_line, O_RDWR); /* uses fd 0 */
+ xdup2(0, 1);
+ xdup2(0, 2);
+ /* copy our original stdin tty's parameters to pty */
+ if (attr_ok == 0)
+ tcsetattr(0, TCSAFLUSH, &tt);
+ if (winsz_ok == 0)
+ ioctl(0, TIOCSWINSZ, (char *)&win);
+ /* set pty as a controlling tty */
+ setsid();
+ ioctl(0, TIOCSCTTY, 0 /* 0: don't forcibly steal */);
+
+ /* Non-ignored signals revert to SIG_DFL on exec anyway */
+ /*signal(SIGCHLD, SIG_DFL);*/
+ execl(shell, shell, shell_opt, shell_arg, (char *) NULL);
+ bb_simple_perror_msg_and_die(shell);
+}
diff --git a/release/src/router/busybox/util-linux/setarch.c b/release/src/router/busybox/util-linux/setarch.c
new file mode 100644
index 00000000..8213382e
--- /dev/null
+++ b/release/src/router/busybox/util-linux/setarch.c
@@ -0,0 +1,48 @@
+/* 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 <sys/personality.h>
+
+#include "libbb.h"
+
+int setarch_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int setarch_main(int argc UNUSED_PARAM, char **argv)
+{
+ int pers;
+
+ /* 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"
+ */
+ if (ENABLE_SETARCH && applet_name[0] == 's'
+ && argv[1] && strncpy(argv[1], "linux", 5)
+ ) {
+ applet_name = argv[1];
+ argv++;
+ }
+ if (applet_name[5] == '6') /* linux64 */
+ pers = PER_LINUX;
+ else if (applet_name[5] == '3') /* linux32 */
+ pers = PER_LINUX32;
+ else
+ bb_show_usage();
+
+ 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_simple_perror_msg_and_die(argv[0]);
+}
diff --git a/release/src/router/busybox/util-linux/swaponoff.c b/release/src/router/busybox/util-linux/swaponoff.c
index 9da70756..863f7734 100644
--- a/release/src/router/busybox/util-linux/swaponoff.c
+++ b/release/src/router/busybox/util-linux/swaponoff.c
@@ -2,120 +2,101 @@
/*
* Mini swapon/swapoff implementation for busybox
*
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under the GPL version 2, see the file LICENSE in this tarball.
*/
-#include <stdio.h>
+#include "libbb.h"
#include <mntent.h>
-#include <dirent.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/mount.h>
#include <sys/swap.h>
-#include "busybox.h"
-
-static int whichApp; /* default SWAPON_APP */
-
-static const int SWAPON_APP = 0;
-static const int SWAPOFF_APP = 1;
-
-
-static int swap_enable_disable(const char *device)
+#if ENABLE_FEATURE_SWAPON_PRI
+struct globals {
+ int flags;
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define g_flags (G.flags)
+#else
+#define g_flags 0
+#endif
+
+static int swap_enable_disable(char *device)
{
int status;
struct stat st;
- if (stat(device, &st) < 0) {
- bb_perror_msg_and_die("cannot stat %s", device);
- }
+ 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_and_die("swap file has holes");
- }
- }
+ if (S_ISREG(st.st_mode))
+ if (st.st_blocks * (off_t)512 < st.st_size)
+ bb_error_msg("warning: swap file has holes");
+#endif
- if (whichApp == SWAPON_APP)
- status = swapon(device, 0);
+ if (applet_name[5] == 'n')
+ status = swapon(device, g_flags);
else
status = swapoff(device);
if (status != 0) {
- bb_perror_msg("%s", device);
- return EXIT_FAILURE;
+ bb_simple_perror_msg(device);
+ return 1;
}
- return EXIT_SUCCESS;
+
+ return 0;
}
static int do_em_all(void)
{
struct mntent *m;
- FILE *f = setmntent("/etc/fstab", "r");
- int err = 0;
+ FILE *f;
+ int err;
+ f = setmntent("/etc/fstab", "r");
if (f == NULL)
bb_perror_msg_and_die("/etc/fstab");
- while ((m = getmntent(f)) != NULL) {
- if (strcmp(m->mnt_type, MNTTYPE_SWAP)==0) {
- if(swap_enable_disable(m->mnt_fsname) == EXIT_FAILURE)
- err++;
- }
- }
+
+ 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;
}
-
-extern int swap_on_off_main(int argc, char **argv)
+int swap_on_off_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int swap_on_off_main(int argc UNUSED_PARAM, char **argv)
{
- if (bb_applet_name[5] == 'f') { /* "swapoff" */
- whichApp = SWAPOFF_APP;
+ int ret;
+
+#if !ENABLE_FEATURE_SWAPON_PRI
+ ret = getopt32(argv, "a");
+#else
+ opt_complementary = "p+";
+ ret = getopt32(argv, (applet_name[5] == 'n') ? "ap:" : "a", &g_flags);
+
+ if (ret & 2) { // -p
+ g_flags = SWAP_FLAG_PREFER |
+ ((g_flags & SWAP_FLAG_PRIO_MASK) << SWAP_FLAG_PRIO_SHIFT);
+ ret &= 1;
}
+#endif
- if (argc != 2) {
- goto usage_and_exit;
- }
- argc--;
- argv++;
-
- /* Parse any options */
- while (**argv == '-') {
- while (*++(*argv))
- switch (**argv) {
- case 'a':
- {
- struct stat statBuf;
-
- if (stat("/etc/fstab", &statBuf) < 0)
- bb_error_msg_and_die("/etc/fstab file missing");
- }
- return do_em_all();
- break;
- default:
- goto usage_and_exit;
- }
- }
- return swap_enable_disable(*argv);
+ if (ret /* & 1: not needed */) // -a
+ return do_em_all();
+
+ argv += optind;
+ if (!*argv)
+ bb_show_usage();
+
+ /* ret = 0; redundant */
+ do {
+ ret += swap_enable_disable(*argv);
+ } while (*++argv);
- usage_and_exit:
- bb_show_usage();
+ return ret;
}
diff --git a/release/src/router/busybox/util-linux/switch_root.c b/release/src/router/busybox/util-linux/switch_root.c
new file mode 100644
index 00000000..21cc9922
--- /dev/null
+++ b/release/src/router/busybox/util-linux/switch_root.c
@@ -0,0 +1,115 @@
+/* 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 "libbb.h"
+#include <sys/vfs.h>
+
+// Make up for header deficiencies.
+#ifndef RAMFS_MAGIC
+#define RAMFS_MAGIC ((unsigned)0x858458f6)
+#endif
+
+#ifndef TMPFS_MAGIC
+#define TMPFS_MAGIC ((unsigned)0x01021994)
+#endif
+
+#ifndef MS_MOVE
+#define MS_MOVE 8192
+#endif
+
+// Recursively delete contents of rootfs.
+static void delete_contents(const char *directory, dev_t rootdev)
+{
+ 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)) {
+ dir = opendir(directory);
+ if (dir) {
+ while ((d = readdir(dir))) {
+ char *newdir = d->d_name;
+
+ // Skip . and ..
+ if (DOT_OR_DOTDOT(newdir))
+ continue;
+
+ // Recurse to delete contents
+ newdir = concat_path_file(directory, newdir);
+ delete_contents(newdir, rootdev);
+ free(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) MAIN_EXTERNALLY_VISIBLE;
+int switch_root_main(int argc UNUSED_PARAM, char **argv)
+{
+ char *newroot, *console = NULL;
+ struct stat st1, st2;
+ struct statfs stfs;
+ dev_t rootdev;
+
+ // Parse args (-c console)
+ opt_complementary = "-2"; // minimum 2 params
+ getopt32(argv, "+c:", &console); // '+': stop parsing at first non-option
+ argv += optind;
+
+ // Change to new root directory and verify it's a different fs.
+ newroot = *argv++;
+
+ xchdir(newroot);
+ if (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 filesystems.)
+ if (lstat("/init", &st1) || !S_ISREG(st1.st_mode) || statfs("/", &stfs)
+ || (((unsigned)stfs.f_type != RAMFS_MAGIC) && ((unsigned)stfs.f_type != TMPFS_MAGIC))
+ || (getpid() != 1)
+ ) {
+ bb_error_msg_and_die("not rootfs");
+ }
+
+ // Zap everything out of rootdev
+ delete_contents("/", rootdev);
+
+ // Overmount / with newdir and chroot into it. The chdir is needed to
+ // recalculate "." and ".." links.
+ if (mount(".", "/", NULL, MS_MOVE, NULL))
+ bb_error_msg_and_die("error moving root");
+ xchroot(".");
+ xchdir("/");
+
+ // If a new console specified, redirect stdin/stdout/stderr to that.
+ if (console) {
+ close(0);
+ xopen(console, O_RDWR);
+ xdup2(0, 1);
+ xdup2(0, 2);
+ }
+
+ // Exec real init. (This is why we must be pid 1.)
+ execv(argv[0], argv);
+ bb_perror_msg_and_die("bad init %s", argv[0]);
+}
diff --git a/release/src/router/busybox/util-linux/umount.c b/release/src/router/busybox/util-linux/umount.c
index 863d5247..5b22bfac 100644
--- a/release/src/router/busybox/util-linux/umount.c
+++ b/release/src/router/busybox/util-linux/umount.c
@@ -2,294 +2,172 @@
/*
* Mini umount implementation for busybox
*
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 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 <limits.h>
-#include <stdio.h>
#include <mntent.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include "busybox.h"
-
-/* Teach libc5 about realpath -- it includes it but the
- * prototype is missing... */
-#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
-extern char *realpath(const char *path, char *resolved_path);
-#endif
-
-static const int MNT_FORCE = 1;
-static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */
-static const int MS_REMOUNT = 32; /* Alter flags of a mounted FS. */
-static const int MS_RDONLY = 1; /* Mount read-only. */
-
-extern int mount (__const char *__special_file, __const char *__dir,
- __const char *__fstype, unsigned long int __rwflag,
- __const void *__data);
-extern int umount (__const char *__special_file);
-extern int umount2 (__const char *__special_file, int __flags);
-
-struct _mtab_entry_t {
- char *device;
- char *mountpt;
- struct _mtab_entry_t *next;
-};
-
-static struct _mtab_entry_t *mtab_cache = NULL;
-
-
+#include "libbb.h"
-#if defined CONFIG_FEATURE_MOUNT_FORCE
-static int doForce = FALSE;
-#endif
-#if defined CONFIG_FEATURE_MOUNT_LOOP
-static int freeLoop = TRUE;
-#endif
-#if defined CONFIG_FEATURE_MTAB_SUPPORT
-static int useMtab = TRUE;
-#endif
-static int umountAll = FALSE;
-static int doRemount = FALSE;
-
-
-
-/* These functions are here because the getmntent functions do not appear
- * to be re-entrant, which leads to all sorts of problems when we try to
- * use them recursively - randolph
- *
- * TODO: Perhaps switch to using Glibc's getmntent_r
- * -Erik
- */
-static void mtab_read(void)
+#if defined(__dietlibc__)
+/* 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
+ * dietlibc-0.30 does not have implementation of getmntent_r() */
+static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
+ char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
{
- struct _mtab_entry_t *entry = NULL;
- struct mntent *e;
- FILE *fp;
-
- if (mtab_cache != NULL)
- return;
-
- if ((fp = setmntent(bb_path_mtab_file, "r")) == NULL) {
- bb_error_msg("Cannot open %s", bb_path_mtab_file);
- return;
- }
- while ((e = getmntent(fp))) {
- entry = xmalloc(sizeof(struct _mtab_entry_t));
- entry->device = strdup(e->mnt_fsname);
- entry->mountpt = strdup(e->mnt_dir);
- entry->next = mtab_cache;
- mtab_cache = entry;
- }
- endmntent(fp);
+ struct mntent* ment = getmntent(stream);
+ return memcpy(result, ment, sizeof(*ment));
}
+#endif
-static char *mtab_getinfo(const char *match, const char which)
+/* ignored: -v -d -t -i */
+#define OPTION_STRING "fldnra" "vdt:i"
+#define OPT_FORCE (1 << 0)
+#define OPT_LAZY (1 << 1)
+#define OPT_FREELOOP (1 << 2)
+#define OPT_NO_MTAB (1 << 3)
+#define OPT_REMOUNT (1 << 4)
+#define OPT_ALL (ENABLE_FEATURE_UMOUNT_ALL ? (1 << 5) : 0)
+
+// These constants from linux/fs.h must match OPT_FORCE and OPT_LAZY,
+// otherwise "doForce" trick below won't work!
+//#define MNT_FORCE 0x00000001 /* Attempt to forcibly umount */
+//#define MNT_DETACH 0x00000002 /* Just detach from the tree */
+
+int umount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int umount_main(int argc UNUSED_PARAM, char **argv)
{
- struct _mtab_entry_t *cur = mtab_cache;
-
- while (cur) {
- if (strcmp(cur->mountpt, match) == 0 ||
- strcmp(cur->device, match) == 0) {
- if (which == MTAB_GETMOUNTPT) {
- return cur->mountpt;
- } else {
-#if !defined CONFIG_FEATURE_MTAB_SUPPORT
- if (strcmp(cur->device, "rootfs") == 0) {
- continue;
- } else if (strcmp(cur->device, "/dev/root") == 0) {
- /* Adjusts device to be the real root device,
- * or leaves device alone if it can't find it */
- cur->device = find_real_root_device_name(cur->device);
- }
-#endif
- return cur->device;
- }
+ int doForce;
+ char *const path = xmalloc(PATH_MAX + 2); /* to save stack */
+ struct mntent me;
+ FILE *fp;
+ char *fstype = NULL;
+ int status = EXIT_SUCCESS;
+ unsigned opt;
+ struct mtab_list {
+ char *dir;
+ char *device;
+ struct mtab_list *next;
+ } *mtl, *m;
+
+ opt = getopt32(argv, OPTION_STRING, &fstype);
+ //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 = NULL;
+
+ // 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("can't open '%s'", bb_path_mtab_file);
+ } else {
+ while (getmntent_r(fp, &me, path, PATH_MAX)) {
+ /* Match fstype if passed */
+ if (!match_fstype(&me, fstype))
+ continue;
+ m = xzalloc(sizeof(*m));
+ m->next = mtl;
+ m->device = xstrdup(me.mnt_fsname);
+ m->dir = xstrdup(me.mnt_dir);
+ mtl = m;
}
- cur = cur->next;
+ endmntent(fp);
}
- return NULL;
-}
-
-static char *mtab_next(void **iter)
-{
- char *mp;
-
- if (iter == NULL || *iter == NULL)
- return NULL;
- mp = ((struct _mtab_entry_t *) (*iter))->mountpt;
- *iter = (void *) ((struct _mtab_entry_t *) (*iter))->next;
- return mp;
-}
-
-static char *mtab_first(void **iter)
-{
- struct _mtab_entry_t *mtab_iter;
-
- if (!iter)
- return NULL;
- mtab_iter = mtab_cache;
- *iter = (void *) mtab_iter;
- return mtab_next(iter);
-}
-
-/* Don't bother to clean up, since exit() does that
- * automagically, so we can save a few bytes */
-#ifdef CONFIG_FEATURE_CLEAN_UP
-static void mtab_free(void)
-{
- struct _mtab_entry_t *this, *next;
- this = mtab_cache;
- while (this) {
- next = this->next;
- free(this->device);
- free(this->mountpt);
- free(this);
- this = next;
+ // If we're not umounting all, we need at least one argument.
+ if (!(opt & OPT_ALL) && !fstype) {
+ if (!argv[0])
+ bb_show_usage();
+ m = NULL;
}
-}
-#endif
-
-static int do_umount(const char *name)
-{
- int status;
- char *blockDevice = mtab_getinfo(name, MTAB_GETDEVICE);
-
- if (blockDevice && strcmp(blockDevice, name) == 0)
- name = mtab_getinfo(blockDevice, MTAB_GETMOUNTPT);
-
- status = umount(name);
-#if defined CONFIG_FEATURE_MOUNT_LOOP
- if (freeLoop && blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9))
- /* this was a loop device, delete it */
- del_loop(blockDevice);
-#endif
-#if defined CONFIG_FEATURE_MOUNT_FORCE
- if (status != 0 && doForce) {
- status = umount2(blockDevice, MNT_FORCE);
- if (status != 0) {
- bb_error_msg_and_die("forced umount of %s failed!", blockDevice);
- }
- }
-#endif
- if (status != 0 && doRemount && errno == EBUSY) {
- status = mount(blockDevice, name, NULL,
- MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
- if (status == 0) {
- bb_error_msg("%s busy - remounted read-only", blockDevice);
- } else {
- bb_error_msg("Cannot remount %s read-only", blockDevice);
+ // 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;
+ // Use command line argument (and look it up in mtab list)
+ else {
+ if (!zapit)
+ break;
+ argv++;
+ realpath(zapit, path);
+ for (m = mtl; m; m = m->next)
+ if (!strcmp(path, m->dir) || !strcmp(path, m->device))
+ break;
}
- }
- if (status == 0) {
-#if defined CONFIG_FEATURE_MTAB_SUPPORT
- if (useMtab)
- erase_mtab(name);
-#endif
- return (TRUE);
- }
- return (FALSE);
-}
-
-static int umount_all(void)
-{
- int status = TRUE;
- char *mountpt;
- void *iter;
-
- for (mountpt = mtab_first(&iter); mountpt; mountpt = mtab_next(&iter)) {
- /* Never umount /proc on a umount -a */
- if (strstr(mountpt, "proc")!= NULL)
- continue;
- if (!do_umount(mountpt)) {
- /* Don't bother retrying the umount on busy devices */
- if (errno == EBUSY) {
- bb_perror_msg("%s", mountpt);
- status = FALSE;
- continue;
- }
- if (!do_umount(mountpt)) {
- printf("Couldn't umount %s on %s: %s\n",
- mountpt, mtab_getinfo(mountpt, MTAB_GETDEVICE),
- strerror(errno));
- status = FALSE;
+ // 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 still can't umount, maybe remount read-only?
+ if (curstat) {
+ if ((opt & OPT_REMOUNT) && errno == EBUSY && m) {
+ // Note! Even if we succeed here, later we should not
+ // free loop device or erase mtab entry!
+ const char *msg = "%s busy - remounted read-only";
+ curstat = mount(m->device, zapit, NULL, MS_REMOUNT|MS_RDONLY, NULL);
+ if (curstat) {
+ msg = "can't remount %s read-only";
+ status = EXIT_FAILURE;
+ }
+ bb_error_msg(msg, m->device);
+ } else {
+ status = EXIT_FAILURE;
+ bb_perror_msg("can't %sumount %s", (doForce ? "forcibly " : ""), 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_FREELOOP) && m)
+ del_loop(m->device);
+ if (ENABLE_FEATURE_MTAB_SUPPORT && !(opt & OPT_NO_MTAB) && m)
+ erase_mtab(m->dir);
}
- }
- return (status);
-}
-extern int umount_main(int argc, char **argv)
-{
- char path[PATH_MAX];
-
- if (argc < 2) {
- bb_show_usage();
- }
-#ifdef CONFIG_FEATURE_CLEAN_UP
- atexit(mtab_free);
-#endif
-
- /* Parse any options */
- while (--argc > 0 && **(++argv) == '-') {
- while (*++(*argv))
- switch (**argv) {
- case 'a':
- umountAll = TRUE;
- break;
-#if defined CONFIG_FEATURE_MOUNT_LOOP
- case 'l':
- freeLoop = FALSE;
+ // 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.
+ if (m) while ((m = m->next) != NULL)
+ if ((opt & OPT_ALL) || !strcmp(path, m->device))
break;
-#endif
-#ifdef CONFIG_FEATURE_MTAB_SUPPORT
- case 'n':
- useMtab = FALSE;
- break;
-#endif
-#ifdef CONFIG_FEATURE_MOUNT_FORCE
- case 'f':
- doForce = TRUE;
- break;
-#endif
- case 'r':
- doRemount = TRUE;
- break;
- case 'v':
- break; /* ignore -v */
- default:
- bb_show_usage();
- }
}
- mtab_read();
- if (umountAll) {
- if (umount_all())
- return EXIT_SUCCESS;
- else
- return EXIT_FAILURE;
+ // 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;
+ }
+ free(path);
}
- if (realpath(*argv, path) == NULL)
- bb_perror_msg_and_die("%s", path);
- if (do_umount(path))
- return EXIT_SUCCESS;
- bb_perror_msg_and_die("%s", *argv);
-}
+ return status;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/Kbuild b/release/src/router/busybox/util-linux/volume_id/Kbuild
new file mode 100644
index 00000000..d78e4ada
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/Kbuild
@@ -0,0 +1,42 @@
+# 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_BLKID) += get_devname.o
+lib-$(CONFIG_FINDFS) += get_devname.o
+lib-$(CONFIG_FEATURE_MOUNT_LABEL) += get_devname.o
+
+lib-$(CONFIG_VOLUMEID) += volume_id.o util.o
+lib-$(CONFIG_FEATURE_VOLUMEID_EXT) += ext.o
+lib-$(CONFIG_FEATURE_VOLUMEID_FAT) += fat.o
+lib-$(CONFIG_FEATURE_VOLUMEID_HFS) += hfs.o
+### lib-$(CONFIG_FEATURE_VOLUMEID_HIGHPOINTRAID) += highpoint.o
+### lib-$(CONFIG_FEATURE_VOLUMEID_ISWRAID) += isw_raid.o
+### lib-$(CONFIG_FEATURE_VOLUMEID_LSIRAID) += lsi_raid.o
+### lib-$(CONFIG_FEATURE_VOLUMEID_VIARAID) += via_raid.o
+### lib-$(CONFIG_FEATURE_VOLUMEID_SILICONRAID) += silicon_raid.o
+### lib-$(CONFIG_FEATURE_VOLUMEID_NVIDIARAID) += nvidia_raid.o
+### lib-$(CONFIG_FEATURE_VOLUMEID_PROMISERAID) += promise_raid.o
+lib-$(CONFIG_FEATURE_VOLUMEID_ISO9660) += iso9660.o
+lib-$(CONFIG_FEATURE_VOLUMEID_JFS) += jfs.o
+lib-$(CONFIG_FEATURE_VOLUMEID_LINUXRAID) += linux_raid.o
+lib-$(CONFIG_FEATURE_VOLUMEID_LINUXSWAP) += linux_swap.o
+### lib-$(CONFIG_FEATURE_VOLUMEID_LVM) += lvm.o
+### lib-$(CONFIG_FEATURE_VOLUMEID_MAC) += mac.o
+### lib-$(CONFIG_FEATURE_VOLUMEID_MSDOS) += msdos.o
+lib-$(CONFIG_FEATURE_VOLUMEID_NTFS) += ntfs.o
+lib-$(CONFIG_FEATURE_VOLUMEID_REISERFS) += reiserfs.o
+lib-$(CONFIG_FEATURE_VOLUMEID_UDF) += udf.o
+### lib-$(CONFIG_FEATURE_VOLUMEID_UFS) += ufs.o
+lib-$(CONFIG_FEATURE_VOLUMEID_XFS) += xfs.o
+lib-$(CONFIG_FEATURE_VOLUMEID_CRAMFS) += cramfs.o
+### lib-$(CONFIG_FEATURE_VOLUMEID_HPFS) += hpfs.o
+lib-$(CONFIG_FEATURE_VOLUMEID_ROMFS) += romfs.o
+lib-$(CONFIG_FEATURE_VOLUMEID_SYSV) += sysv.o
+### lib-$(CONFIG_FEATURE_VOLUMEID_MINIX) += minix.o
+lib-$(CONFIG_FEATURE_VOLUMEID_LUKS) += luks.o
+lib-$(CONFIG_FEATURE_VOLUMEID_OCFS2) += ocfs2.o
diff --git a/release/src/router/busybox/util-linux/volume_id/cramfs.c b/release/src/router/busybox/util-linux/volume_id/cramfs.c
new file mode 100644
index 00000000..dd939e49
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/cramfs.c
@@ -0,0 +1,59 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct cramfs_super {
+ uint32_t magic;
+ uint32_t size;
+ uint32_t flags;
+ uint32_t future;
+ uint8_t signature[16];
+ struct cramfs_info {
+ uint32_t crc;
+ uint32_t edition;
+ uint32_t blocks;
+ uint32_t files;
+ } __attribute__((__packed__)) info;
+ uint8_t name[16];
+} __attribute__((__packed__));
+
+int volume_id_probe_cramfs(struct volume_id *id /*,uint64_t off*/)
+{
+#define off ((uint64_t)0)
+ struct cramfs_super *cs;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ cs = volume_id_get_buffer(id, off, 0x200);
+ if (cs == NULL)
+ return -1;
+
+ if (cs->magic == cpu_to_be32(0x453dcd28)) {
+// volume_id_set_label_raw(id, cs->name, 16);
+ volume_id_set_label_string(id, cs->name, 16);
+
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+// id->type = "cramfs";
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/ext.c b/release/src/router/busybox/util-linux/volume_id/ext.c
new file mode 100644
index 00000000..b052e04c
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/ext.c
@@ -0,0 +1,74 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct ext2_super_block {
+ uint32_t inodes_count;
+ uint32_t blocks_count;
+ uint32_t r_blocks_count;
+ uint32_t free_blocks_count;
+ uint32_t free_inodes_count;
+ uint32_t first_data_block;
+ uint32_t log_block_size;
+ uint32_t dummy3[7];
+ uint8_t magic[2];
+ uint16_t state;
+ uint32_t dummy5[8];
+ uint32_t feature_compat;
+ uint32_t feature_incompat;
+ uint32_t feature_ro_compat;
+ uint8_t uuid[16];
+ uint8_t volume_name[16];
+} __attribute__((__packed__));
+
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x00000004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x00000008
+#define EXT_SUPERBLOCK_OFFSET 0x400
+
+int volume_id_probe_ext(struct volume_id *id /*,uint64_t off*/)
+{
+#define off ((uint64_t)0)
+ struct ext2_super_block *es;
+
+ dbg("ext: probing at offset 0x%llx", (unsigned long long) off);
+
+ es = volume_id_get_buffer(id, off + EXT_SUPERBLOCK_OFFSET, 0x200);
+ if (es == NULL)
+ return -1;
+
+ if (es->magic[0] != 0123 || es->magic[1] != 0357) {
+ dbg("ext: no magic found");
+ return -1;
+ }
+
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+// volume_id_set_label_raw(id, es->volume_name, 16);
+ volume_id_set_label_string(id, es->volume_name, 16);
+ volume_id_set_uuid(id, es->uuid, UUID_DCE);
+ dbg("ext: label '%s' uuid '%s'", id->label, id->uuid);
+
+// if ((le32_to_cpu(es->feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0)
+// id->type = "ext3";
+// else
+// id->type = "ext2";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/fat.c b/release/src/router/busybox/util-linux/volume_id/fat.c
new file mode 100644
index 00000000..352040f5
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/fat.c
@@ -0,0 +1,332 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+/* linux/msdos_fs.h says: */
+#define FAT12_MAX 0xff4
+#define FAT16_MAX 0xfff4
+#define FAT32_MAX 0x0ffffff6
+
+#define FAT_ATTR_VOLUME_ID 0x08
+#define FAT_ATTR_DIR 0x10
+#define FAT_ATTR_LONG_NAME 0x0f
+#define FAT_ATTR_MASK 0x3f
+#define FAT_ENTRY_FREE 0xe5
+
+struct vfat_super_block {
+ uint8_t boot_jump[3];
+ uint8_t sysid[8];
+ uint16_t sector_size_bytes;
+ uint8_t sectors_per_cluster;
+ uint16_t reserved_sct;
+ uint8_t fats;
+ uint16_t dir_entries;
+ uint16_t sectors;
+ uint8_t media;
+ uint16_t fat_length;
+ uint16_t secs_track;
+ uint16_t heads;
+ uint32_t hidden;
+ uint32_t total_sect;
+ union {
+ struct fat_super_block {
+ uint8_t unknown[3];
+ uint8_t serno[4];
+ uint8_t label[11];
+ uint8_t magic[8];
+ uint8_t dummy2[192];
+ uint8_t pmagic[2];
+ } __attribute__((__packed__)) fat;
+ struct fat32_super_block {
+ uint32_t fat32_length;
+ uint16_t flags;
+ uint8_t version[2];
+ uint32_t root_cluster;
+ uint16_t insfo_sector;
+ uint16_t backup_boot;
+ uint16_t reserved2[6];
+ uint8_t unknown[3];
+ uint8_t serno[4];
+ uint8_t label[11];
+ uint8_t magic[8];
+ uint8_t dummy2[164];
+ uint8_t pmagic[2];
+ } __attribute__((__packed__)) fat32;
+ } __attribute__((__packed__)) type;
+} __attribute__((__packed__));
+
+struct vfat_dir_entry {
+ uint8_t name[11];
+ uint8_t attr;
+ uint16_t time_creat;
+ uint16_t date_creat;
+ uint16_t time_acc;
+ uint16_t date_acc;
+ uint16_t cluster_high;
+ uint16_t time_write;
+ uint16_t date_write;
+ uint16_t cluster_low;
+ uint32_t size;
+} __attribute__((__packed__));
+
+static uint8_t *get_attr_volume_id(struct vfat_dir_entry *dir, int count)
+{
+ for (;--count >= 0; dir++) {
+ /* end marker */
+ if (dir->name[0] == 0x00) {
+ dbg("end of dir");
+ break;
+ }
+
+ /* empty entry */
+ if (dir->name[0] == FAT_ENTRY_FREE)
+ continue;
+
+ /* long name */
+ if ((dir->attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME)
+ continue;
+
+ if ((dir->attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) {
+ /* labels do not have file data */
+ if (dir->cluster_high != 0 || dir->cluster_low != 0)
+ continue;
+
+ dbg("found ATTR_VOLUME_ID id in root dir");
+ return dir->name;
+ }
+
+ dbg("skip dir entry");
+ }
+
+ return NULL;
+}
+
+int volume_id_probe_vfat(struct volume_id *id /*,uint64_t fat_partition_off*/)
+{
+#define fat_partition_off ((uint64_t)0)
+ struct vfat_super_block *vs;
+ struct vfat_dir_entry *dir;
+ uint16_t sector_size_bytes;
+ uint16_t dir_entries;
+ uint32_t sect_count;
+ uint16_t reserved_sct;
+ uint32_t fat_size_sct;
+ uint32_t root_cluster;
+ uint32_t dir_size_sct;
+ uint32_t cluster_count;
+ uint64_t root_start_off;
+ uint32_t start_data_sct;
+ uint8_t *buf;
+ uint32_t buf_size;
+ uint8_t *label = NULL;
+ uint32_t next_cluster;
+ int maxloop;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) fat_partition_off);
+
+ vs = volume_id_get_buffer(id, fat_partition_off, 0x200);
+ if (vs == NULL)
+ return -1;
+
+ /* believe only that's fat, don't trust the version
+ * the cluster_count will tell us
+ */
+ if (memcmp(vs->sysid, "NTFS", 4) == 0)
+ return -1;
+
+ if (memcmp(vs->type.fat32.magic, "MSWIN", 5) == 0)
+ goto valid;
+
+ if (memcmp(vs->type.fat32.magic, "FAT32 ", 8) == 0)
+ goto valid;
+
+ if (memcmp(vs->type.fat.magic, "FAT16 ", 8) == 0)
+ goto valid;
+
+ if (memcmp(vs->type.fat.magic, "MSDOS", 5) == 0)
+ goto valid;
+
+ if (memcmp(vs->type.fat.magic, "FAT12 ", 8) == 0)
+ goto valid;
+
+ /*
+ * There are old floppies out there without a magic, so we check
+ * for well known values and guess if it's a fat volume
+ */
+
+ /* boot jump address check */
+ if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) &&
+ vs->boot_jump[0] != 0xe9)
+ return -1;
+
+ /* heads check */
+ if (vs->heads == 0)
+ return -1;
+
+ /* cluster size check */
+ if (vs->sectors_per_cluster == 0 ||
+ (vs->sectors_per_cluster & (vs->sectors_per_cluster-1)))
+ return -1;
+
+ /* media check */
+ if (vs->media < 0xf8 && vs->media != 0xf0)
+ return -1;
+
+ /* fat count*/
+ if (vs->fats != 2)
+ return -1;
+
+ valid:
+ /* sector size check */
+ sector_size_bytes = le16_to_cpu(vs->sector_size_bytes);
+ if (sector_size_bytes != 0x200 && sector_size_bytes != 0x400 &&
+ sector_size_bytes != 0x800 && sector_size_bytes != 0x1000)
+ return -1;
+
+ dbg("sector_size_bytes 0x%x", sector_size_bytes);
+ dbg("sectors_per_cluster 0x%x", vs->sectors_per_cluster);
+
+ reserved_sct = le16_to_cpu(vs->reserved_sct);
+ dbg("reserved_sct 0x%x", reserved_sct);
+
+ sect_count = le16_to_cpu(vs->sectors);
+ if (sect_count == 0)
+ sect_count = le32_to_cpu(vs->total_sect);
+ dbg("sect_count 0x%x", sect_count);
+
+ fat_size_sct = le16_to_cpu(vs->fat_length);
+ if (fat_size_sct == 0)
+ fat_size_sct = le32_to_cpu(vs->type.fat32.fat32_length);
+ fat_size_sct *= vs->fats;
+ dbg("fat_size_sct 0x%x", fat_size_sct);
+
+ dir_entries = le16_to_cpu(vs->dir_entries);
+ dir_size_sct = ((dir_entries * sizeof(struct vfat_dir_entry)) +
+ (sector_size_bytes-1)) / sector_size_bytes;
+ dbg("dir_size_sct 0x%x", dir_size_sct);
+
+ cluster_count = sect_count - (reserved_sct + fat_size_sct + dir_size_sct);
+ cluster_count /= vs->sectors_per_cluster;
+ dbg("cluster_count 0x%x", cluster_count);
+
+// if (cluster_count < FAT12_MAX) {
+// strcpy(id->type_version, "FAT12");
+// } else if (cluster_count < FAT16_MAX) {
+// strcpy(id->type_version, "FAT16");
+// } else {
+// strcpy(id->type_version, "FAT32");
+// goto fat32;
+// }
+ if (cluster_count >= FAT16_MAX)
+ goto fat32;
+
+ /* the label may be an attribute in the root directory */
+ root_start_off = (reserved_sct + fat_size_sct) * sector_size_bytes;
+ dbg("root dir start 0x%llx", (unsigned long long) root_start_off);
+ dbg("expected entries 0x%x", dir_entries);
+
+ buf_size = dir_entries * sizeof(struct vfat_dir_entry);
+ buf = volume_id_get_buffer(id, fat_partition_off + root_start_off, buf_size);
+ if (buf == NULL)
+ goto ret;
+
+ label = get_attr_volume_id((struct vfat_dir_entry*) buf, dir_entries);
+
+ vs = volume_id_get_buffer(id, fat_partition_off, 0x200);
+ if (vs == NULL)
+ return -1;
+
+ if (label != NULL && memcmp(label, "NO NAME ", 11) != 0) {
+// volume_id_set_label_raw(id, label, 11);
+ volume_id_set_label_string(id, label, 11);
+ } else if (memcmp(vs->type.fat.label, "NO NAME ", 11) != 0) {
+// volume_id_set_label_raw(id, vs->type.fat.label, 11);
+ volume_id_set_label_string(id, vs->type.fat.label, 11);
+ }
+ volume_id_set_uuid(id, vs->type.fat.serno, UUID_DOS);
+ goto ret;
+
+ fat32:
+ /* FAT32 root dir is a cluster chain like any other directory */
+ buf_size = vs->sectors_per_cluster * sector_size_bytes;
+ root_cluster = le32_to_cpu(vs->type.fat32.root_cluster);
+ start_data_sct = reserved_sct + fat_size_sct;
+
+ next_cluster = root_cluster;
+ maxloop = 100;
+ while (--maxloop) {
+ uint64_t next_off_sct;
+ uint64_t next_off;
+ uint64_t fat_entry_off;
+ int count;
+
+ dbg("next_cluster 0x%x", (unsigned)next_cluster);
+ next_off_sct = (uint64_t)(next_cluster - 2) * vs->sectors_per_cluster;
+ next_off = (start_data_sct + next_off_sct) * sector_size_bytes;
+ dbg("cluster offset 0x%llx", (unsigned long long) next_off);
+
+ /* get cluster */
+ buf = volume_id_get_buffer(id, fat_partition_off + next_off, buf_size);
+ if (buf == NULL)
+ goto ret;
+
+ dir = (struct vfat_dir_entry*) buf;
+ count = buf_size / sizeof(struct vfat_dir_entry);
+ dbg("expected entries 0x%x", count);
+
+ label = get_attr_volume_id(dir, count);
+ if (label)
+ break;
+
+ /* get FAT entry */
+ fat_entry_off = (reserved_sct * sector_size_bytes) + (next_cluster * sizeof(uint32_t));
+ dbg("fat_entry_off 0x%llx", (unsigned long long)fat_entry_off);
+ buf = volume_id_get_buffer(id, fat_partition_off + fat_entry_off, buf_size);
+ if (buf == NULL)
+ goto ret;
+
+ /* set next cluster */
+ next_cluster = le32_to_cpu(*(uint32_t*)buf) & 0x0fffffff;
+ if (next_cluster < 2 || next_cluster > FAT32_MAX)
+ break;
+ }
+ if (maxloop == 0)
+ dbg("reached maximum follow count of root cluster chain, give up");
+
+ vs = volume_id_get_buffer(id, fat_partition_off, 0x200);
+ if (vs == NULL)
+ return -1;
+
+ if (label != NULL && memcmp(label, "NO NAME ", 11) != 0) {
+// volume_id_set_label_raw(id, label, 11);
+ volume_id_set_label_string(id, label, 11);
+ } else if (memcmp(vs->type.fat32.label, "NO NAME ", 11) != 0) {
+// volume_id_set_label_raw(id, vs->type.fat32.label, 11);
+ volume_id_set_label_string(id, vs->type.fat32.label, 11);
+ }
+ volume_id_set_uuid(id, vs->type.fat32.serno, UUID_DOS);
+
+ ret:
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+// id->type = "vfat";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/get_devname.c b/release/src/router/busybox/util-linux/volume_id/get_devname.c
new file mode 100644
index 00000000..ac69f78c
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/get_devname.c
@@ -0,0 +1,252 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Support functions for mounting devices by label/uuid
+ *
+ * Copyright (C) 2006 by Jason Schoon <floydpink@gmail.com>
+ * Some portions cribbed from e2fsprogs, util-linux, dosfstools
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "volume_id_internal.h"
+
+//#define BLKGETSIZE64 _IOR(0x12,114,size_t)
+
+static struct uuidCache_s {
+ struct uuidCache_s *next;
+// int major, minor;
+ char *device;
+ char *label;
+ char *uc_uuid; /* prefix makes it easier to grep for */
+} *uuidCache;
+
+/* Returns !0 on error.
+ * Otherwise, returns malloc'ed strings for label and uuid
+ * (and they can't be NULL, although they can be "").
+ * NB: closes fd. */
+static int
+get_label_uuid(int fd, char **label, char **uuid)
+{
+ int rv = 1;
+ uint64_t size;
+ struct volume_id *vid;
+
+ /* fd is owned by vid now */
+ vid = volume_id_open_node(fd);
+
+ if (ioctl(/*vid->*/fd, BLKGETSIZE64, &size) != 0)
+ size = 0;
+
+ if (volume_id_probe_all(vid, /*0,*/ size) != 0)
+ goto ret;
+
+ if (vid->label[0] != '\0' || vid->uuid[0] != '\0') {
+ *label = xstrndup(vid->label, sizeof(vid->label));
+ *uuid = xstrndup(vid->uuid, sizeof(vid->uuid));
+ dbg("found label '%s', uuid '%s' on %s", *label, *uuid, device);
+ rv = 0;
+ }
+ ret:
+ free_volume_id(vid); /* also closes fd */
+ return rv;
+}
+
+/* NB: we take ownership of (malloc'ed) label and uuid */
+static void
+uuidcache_addentry(char *device, /*int major, int minor,*/ char *label, char *uuid)
+{
+ struct uuidCache_s *last;
+
+ if (!uuidCache) {
+ last = uuidCache = xzalloc(sizeof(*uuidCache));
+ } else {
+ for (last = uuidCache; last->next; last = last->next)
+ continue;
+ last->next = xzalloc(sizeof(*uuidCache));
+ last = last->next;
+ }
+ /*last->next = NULL; - xzalloc did it*/
+// last->major = major;
+// last->minor = minor;
+ last->device = device;
+ last->label = label;
+ last->uc_uuid = uuid;
+}
+
+/* If get_label_uuid() on device_name returns success,
+ * add a cache entry for this device.
+ * If device node does not exist, it will be temporarily created. */
+static int FAST_FUNC
+uuidcache_check_device(const char *device,
+ struct stat *statbuf,
+ void *userData UNUSED_PARAM,
+ int depth UNUSED_PARAM)
+{
+ char *uuid = uuid; /* for compiler */
+ char *label = label;
+ int fd;
+
+ if (!S_ISBLK(statbuf->st_mode))
+ return TRUE;
+
+ fd = open(device, O_RDONLY);
+ if (fd < 0)
+ return TRUE;
+
+ /* get_label_uuid() closes fd in all cases (success & failure) */
+ if (get_label_uuid(fd, &label, &uuid) == 0) {
+ /* uuidcache_addentry() takes ownership of all three params */
+ uuidcache_addentry(xstrdup(device), /*ma, mi,*/ label, uuid);
+ }
+ return TRUE;
+}
+
+static void
+uuidcache_init(void)
+{
+ if (uuidCache)
+ return;
+
+ /* We were scanning /proc/partitions
+ * and /proc/sys/dev/cdrom/info here.
+ * Missed volume managers. I see that "standard" blkid uses these:
+ * /dev/mapper/control
+ * /proc/devices
+ * /proc/evms/volumes
+ * /proc/lvm/VGs
+ * This is unacceptably complex. Let's just scan /dev.
+ * (Maybe add scanning of /sys/block/XXX/dev for devices
+ * somehow not having their /dev/XXX entries created?) */
+
+ recursive_action("/dev", ACTION_RECURSE,
+ uuidcache_check_device, /* file_action */
+ NULL, /* dir_action */
+ NULL, /* userData */
+ 0 /* depth */);
+}
+
+#define UUID 1
+#define VOL 2
+
+#ifdef UNUSED
+static char *
+get_spec_by_x(int n, const char *t, int *majorPtr, int *minorPtr)
+{
+ struct uuidCache_s *uc;
+
+ uuidcache_init();
+ uc = uuidCache;
+
+ while (uc) {
+ switch (n) {
+ case UUID:
+ if (strcmp(t, uc->uc_uuid) == 0) {
+ *majorPtr = uc->major;
+ *minorPtr = uc->minor;
+ return uc->device;
+ }
+ break;
+ case VOL:
+ if (strcmp(t, uc->label) == 0) {
+ *majorPtr = uc->major;
+ *minorPtr = uc->minor;
+ return uc->device;
+ }
+ break;
+ }
+ uc = uc->next;
+ }
+ return NULL;
+}
+
+static unsigned char
+fromhex(char c)
+{
+ if (isdigit(c))
+ return (c - '0');
+ return ((c|0x20) - 'a' + 10);
+}
+
+static char *
+get_spec_by_uuid(const char *s, int *major, int *minor)
+{
+ unsigned char uuid[16];
+ int i;
+
+ if (strlen(s) != 36 || s[8] != '-' || s[13] != '-'
+ || s[18] != '-' || s[23] != '-'
+ ) {
+ goto bad_uuid;
+ }
+ for (i = 0; i < 16; i++) {
+ if (*s == '-')
+ s++;
+ if (!isxdigit(s[0]) || !isxdigit(s[1]))
+ goto bad_uuid;
+ uuid[i] = ((fromhex(s[0]) << 4) | fromhex(s[1]));
+ s += 2;
+ }
+ return get_spec_by_x(UUID, (char *)uuid, major, minor);
+
+ bad_uuid:
+ fprintf(stderr, _("mount: bad UUID"));
+ return 0;
+}
+
+static char *
+get_spec_by_volume_label(const char *s, int *major, int *minor)
+{
+ return get_spec_by_x(VOL, s, major, minor);
+}
+#endif // UNUSED
+
+/* Used by blkid */
+void display_uuid_cache(void)
+{
+ struct uuidCache_s *u;
+
+ uuidcache_init();
+ u = uuidCache;
+ while (u) {
+ printf("%s:", u->device);
+ if (u->label[0])
+ printf(" LABEL=\"%s\"", u->label);
+ if (u->uc_uuid[0])
+ printf(" UUID=\"%s\"", u->uc_uuid);
+ bb_putchar('\n');
+ u = u->next;
+ }
+}
+
+/* Used by mount and findfs */
+
+char *get_devname_from_label(const char *spec)
+{
+ struct uuidCache_s *uc;
+
+ uuidcache_init();
+ uc = uuidCache;
+ while (uc) {
+ if (uc->label[0] && strcmp(spec, uc->label) == 0) {
+ return xstrdup(uc->device);
+ }
+ uc = uc->next;
+ }
+ return NULL;
+}
+
+char *get_devname_from_uuid(const char *spec)
+{
+ struct uuidCache_s *uc;
+
+ uuidcache_init();
+ uc = uuidCache;
+ while (uc) {
+ /* case of hex numbers doesn't matter */
+ if (strcasecmp(spec, uc->uc_uuid) == 0) {
+ return xstrdup(uc->device);
+ }
+ uc = uc->next;
+ }
+ return NULL;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/hfs.c b/release/src/router/busybox/util-linux/volume_id/hfs.c
new file mode 100644
index 00000000..f99b895c
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/hfs.c
@@ -0,0 +1,292 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct hfs_finder_info{
+ uint32_t boot_folder;
+ uint32_t start_app;
+ uint32_t open_folder;
+ uint32_t os9_folder;
+ uint32_t reserved;
+ uint32_t osx_folder;
+ uint8_t id[8];
+} __attribute__((__packed__));
+
+struct hfs_mdb {
+ uint8_t signature[2];
+ uint32_t cr_date;
+ uint32_t ls_Mod;
+ uint16_t atrb;
+ uint16_t nm_fls;
+ uint16_t vbm_st;
+ uint16_t alloc_ptr;
+ uint16_t nm_al_blks;
+ uint32_t al_blk_size;
+ uint32_t clp_size;
+ uint16_t al_bl_st;
+ uint32_t nxt_cnid;
+ uint16_t free_bks;
+ uint8_t label_len;
+ uint8_t label[27];
+ uint32_t vol_bkup;
+ uint16_t vol_seq_num;
+ uint32_t wr_cnt;
+ uint32_t xt_clump_size;
+ uint32_t ct_clump_size;
+ uint16_t num_root_dirs;
+ uint32_t file_count;
+ uint32_t dir_count;
+ struct hfs_finder_info finder_info;
+ uint8_t embed_sig[2];
+ uint16_t embed_startblock;
+ uint16_t embed_blockcount;
+} __attribute__((__packed__));
+
+struct hfsplus_bnode_descriptor {
+ uint32_t next;
+ uint32_t prev;
+ uint8_t type;
+ uint8_t height;
+ uint16_t num_recs;
+ uint16_t reserved;
+} __attribute__((__packed__));
+
+struct hfsplus_bheader_record {
+ uint16_t depth;
+ uint32_t root;
+ uint32_t leaf_count;
+ uint32_t leaf_head;
+ uint32_t leaf_tail;
+ uint16_t node_size;
+} __attribute__((__packed__));
+
+struct hfsplus_catalog_key {
+ uint16_t key_len;
+ uint32_t parent_id;
+ uint16_t unicode_len;
+ uint8_t unicode[255 * 2];
+} __attribute__((__packed__));
+
+struct hfsplus_extent {
+ uint32_t start_block;
+ uint32_t block_count;
+} __attribute__((__packed__));
+
+#define HFSPLUS_EXTENT_COUNT 8
+struct hfsplus_fork {
+ uint64_t total_size;
+ uint32_t clump_size;
+ uint32_t total_blocks;
+ struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
+} __attribute__((__packed__));
+
+struct hfsplus_vol_header {
+ uint8_t signature[2];
+ uint16_t version;
+ uint32_t attributes;
+ uint32_t last_mount_vers;
+ uint32_t reserved;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t backup_date;
+ uint32_t checked_date;
+ uint32_t file_count;
+ uint32_t folder_count;
+ uint32_t blocksize;
+ uint32_t total_blocks;
+ uint32_t free_blocks;
+ uint32_t next_alloc;
+ uint32_t rsrc_clump_sz;
+ uint32_t data_clump_sz;
+ uint32_t next_cnid;
+ uint32_t write_count;
+ uint64_t encodings_bmp;
+ struct hfs_finder_info finder_info;
+ struct hfsplus_fork alloc_file;
+ struct hfsplus_fork ext_file;
+ struct hfsplus_fork cat_file;
+ struct hfsplus_fork attr_file;
+ struct hfsplus_fork start_file;
+} __attribute__((__packed__));
+
+#define HFS_SUPERBLOCK_OFFSET 0x400
+#define HFS_NODE_LEAF 0xff
+#define HFSPLUS_POR_CNID 1
+
+int volume_id_probe_hfs_hfsplus(struct volume_id *id /*,uint64_t off*/)
+{
+ uint64_t off = 0;
+ unsigned blocksize;
+ unsigned cat_block;
+ unsigned ext_block_start;
+ unsigned ext_block_count;
+ int ext;
+ unsigned leaf_node_head;
+ unsigned leaf_node_count;
+ unsigned leaf_node_size;
+ unsigned leaf_block;
+ uint64_t leaf_off;
+ unsigned alloc_block_size;
+ unsigned alloc_first_block;
+ unsigned embed_first_block;
+ unsigned record_count;
+ struct hfsplus_vol_header *hfsplus;
+ struct hfsplus_bnode_descriptor *descr;
+ struct hfsplus_bheader_record *bnode;
+ struct hfsplus_catalog_key *key;
+ unsigned label_len;
+ struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
+ struct hfs_mdb *hfs;
+ const uint8_t *buf;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ buf = volume_id_get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ hfs = (struct hfs_mdb *) buf;
+ if (hfs->signature[0] != 'B' || hfs->signature[1] != 'D')
+ goto checkplus;
+
+ /* it may be just a hfs wrapper for hfs+ */
+ if (hfs->embed_sig[0] == 'H' && hfs->embed_sig[1] == '+') {
+ alloc_block_size = be32_to_cpu(hfs->al_blk_size);
+ dbg("alloc_block_size 0x%x", alloc_block_size);
+
+ alloc_first_block = be16_to_cpu(hfs->al_bl_st);
+ dbg("alloc_first_block 0x%x", alloc_first_block);
+
+ embed_first_block = be16_to_cpu(hfs->embed_startblock);
+ dbg("embed_first_block 0x%x", embed_first_block);
+
+ off += (alloc_first_block * 512) +
+ (embed_first_block * alloc_block_size);
+ dbg("hfs wrapped hfs+ found at offset 0x%llx", (unsigned long long) off);
+
+ buf = volume_id_get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
+ if (buf == NULL)
+ return -1;
+ goto checkplus;
+ }
+
+ if (hfs->label_len > 0 && hfs->label_len < 28) {
+// volume_id_set_label_raw(id, hfs->label, hfs->label_len);
+ volume_id_set_label_string(id, hfs->label, hfs->label_len) ;
+ }
+
+ volume_id_set_uuid(id, hfs->finder_info.id, UUID_HFS);
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+// id->type = "hfs";
+
+ return 0;
+
+ checkplus:
+ hfsplus = (struct hfsplus_vol_header *) buf;
+ if (hfs->signature[0] == 'H')
+ if (hfs->signature[1] == '+' || hfs->signature[1] == 'X')
+ goto hfsplus;
+ return -1;
+
+ hfsplus:
+ volume_id_set_uuid(id, hfsplus->finder_info.id, UUID_HFS);
+
+ blocksize = be32_to_cpu(hfsplus->blocksize);
+ dbg("blocksize %u", blocksize);
+
+ memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
+ cat_block = be32_to_cpu(extents[0].start_block);
+ dbg("catalog start block 0x%x", cat_block);
+
+ buf = volume_id_get_buffer(id, off + (cat_block * blocksize), 0x2000);
+ if (buf == NULL)
+ goto found;
+
+ bnode = (struct hfsplus_bheader_record *)
+ &buf[sizeof(struct hfsplus_bnode_descriptor)];
+
+ leaf_node_head = be32_to_cpu(bnode->leaf_head);
+ dbg("catalog leaf node 0x%x", leaf_node_head);
+
+ leaf_node_size = be16_to_cpu(bnode->node_size);
+ dbg("leaf node size 0x%x", leaf_node_size);
+
+ leaf_node_count = be32_to_cpu(bnode->leaf_count);
+ dbg("leaf node count 0x%x", leaf_node_count);
+ if (leaf_node_count == 0)
+ goto found;
+
+ leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
+
+ /* get physical location */
+ for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) {
+ ext_block_start = be32_to_cpu(extents[ext].start_block);
+ ext_block_count = be32_to_cpu(extents[ext].block_count);
+ dbg("extent start block 0x%x, count 0x%x", ext_block_start, ext_block_count);
+
+ if (ext_block_count == 0)
+ goto found;
+
+ /* this is our extent */
+ if (leaf_block < ext_block_count)
+ break;
+
+ leaf_block -= ext_block_count;
+ }
+ if (ext == HFSPLUS_EXTENT_COUNT)
+ goto found;
+ dbg("found block in extent %i", ext);
+
+ leaf_off = (ext_block_start + leaf_block) * blocksize;
+
+ buf = volume_id_get_buffer(id, off + leaf_off, leaf_node_size);
+ if (buf == NULL)
+ goto found;
+
+ descr = (struct hfsplus_bnode_descriptor *) buf;
+ dbg("descriptor type 0x%x", descr->type);
+
+ record_count = be16_to_cpu(descr->num_recs);
+ dbg("number of records %u", record_count);
+ if (record_count == 0)
+ goto found;
+
+ if (descr->type != HFS_NODE_LEAF)
+ goto found;
+
+ key = (struct hfsplus_catalog_key *)
+ &buf[sizeof(struct hfsplus_bnode_descriptor)];
+
+ dbg("parent id 0x%x", be32_to_cpu(key->parent_id));
+ if (key->parent_id != cpu_to_be32(HFSPLUS_POR_CNID))
+ goto found;
+
+ label_len = be16_to_cpu(key->unicode_len) * 2;
+ dbg("label unicode16 len %i", label_len);
+// volume_id_set_label_raw(id, key->unicode, label_len);
+ volume_id_set_label_unicode16(id, key->unicode, BE, label_len);
+
+ found:
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+// id->type = "hfsplus";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/iso9660.c b/release/src/router/busybox/util-linux/volume_id/iso9660.c
new file mode 100644
index 00000000..82f5e484
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/iso9660.c
@@ -0,0 +1,120 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+#define ISO_SUPERBLOCK_OFFSET 0x8000
+#define ISO_SECTOR_SIZE 0x800
+#define ISO_VD_OFFSET (ISO_SUPERBLOCK_OFFSET + ISO_SECTOR_SIZE)
+#define ISO_VD_PRIMARY 0x1
+#define ISO_VD_SUPPLEMENTARY 0x2
+#define ISO_VD_END 0xff
+#define ISO_VD_MAX 16
+
+struct iso_volume_descriptor {
+ uint8_t vd_type;
+ uint8_t vd_id[5];
+ uint8_t vd_version;
+ uint8_t flags;
+ uint8_t system_id[32];
+ uint8_t volume_id[32];
+ uint8_t unused[8];
+ uint8_t space_size[8];
+ uint8_t escape_sequences[8];
+} __attribute__((__packed__));
+
+struct high_sierra_volume_descriptor {
+ uint8_t foo[8];
+ uint8_t type;
+ uint8_t id[4];
+ uint8_t version;
+} __attribute__((__packed__));
+
+int volume_id_probe_iso9660(struct volume_id *id /*,uint64_t off*/)
+{
+#define off ((uint64_t)0)
+ uint8_t *buf;
+ struct iso_volume_descriptor *is;
+ struct high_sierra_volume_descriptor *hs;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ buf = volume_id_get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ is = (struct iso_volume_descriptor *) buf;
+
+ if (memcmp(is->vd_id, "CD001", 5) == 0) {
+ int vd_offset;
+ int i;
+
+ dbg("read label from PVD");
+// volume_id_set_label_raw(id, is->volume_id, 32);
+ volume_id_set_label_string(id, is->volume_id, 32);
+
+ dbg("looking for SVDs");
+ vd_offset = ISO_VD_OFFSET;
+ for (i = 0; i < ISO_VD_MAX; i++) {
+ uint8_t svd_label[64];
+
+ is = volume_id_get_buffer(id, off + vd_offset, 0x200);
+ if (is == NULL || is->vd_type == ISO_VD_END)
+ break;
+ if (is->vd_type != ISO_VD_SUPPLEMENTARY)
+ continue;
+
+ dbg("found SVD at offset 0x%llx", (unsigned long long) (off + vd_offset));
+ if (memcmp(is->escape_sequences, "%/@", 3) == 0
+ || memcmp(is->escape_sequences, "%/C", 3) == 0
+ || memcmp(is->escape_sequences, "%/E", 3) == 0
+ ) {
+ dbg("Joliet extension found");
+ volume_id_set_unicode16((char *)svd_label, sizeof(svd_label), is->volume_id, BE, 32);
+ if (memcmp(id->label, svd_label, 16) == 0) {
+ dbg("SVD label is identical, use the possibly longer PVD one");
+ break;
+ }
+
+// volume_id_set_label_raw(id, is->volume_id, 32);
+ volume_id_set_label_string(id, svd_label, 32);
+// strcpy(id->type_version, "Joliet Extension");
+ goto found;
+ }
+ vd_offset += ISO_SECTOR_SIZE;
+ }
+ goto found;
+ }
+
+ hs = (struct high_sierra_volume_descriptor *) buf;
+
+ if (memcmp(hs->id, "CDROM", 5) == 0) {
+// strcpy(id->type_version, "High Sierra");
+ goto found;
+ }
+
+ return -1;
+
+ found:
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+// id->type = "iso9660";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/jfs.c b/release/src/router/busybox/util-linux/volume_id/jfs.c
new file mode 100644
index 00000000..4c39e537
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/jfs.c
@@ -0,0 +1,60 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct jfs_super_block {
+ uint8_t magic[4];
+ uint32_t version;
+ uint64_t size;
+ uint32_t bsize;
+ uint32_t dummy1;
+ uint32_t pbsize;
+ uint32_t dummy2[27];
+ uint8_t uuid[16];
+ uint8_t label[16];
+ uint8_t loguuid[16];
+} __attribute__((__packed__));
+
+#define JFS_SUPERBLOCK_OFFSET 0x8000
+
+int volume_id_probe_jfs(struct volume_id *id /*,uint64_t off*/)
+{
+#define off ((uint64_t)0)
+ struct jfs_super_block *js;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ js = volume_id_get_buffer(id, off + JFS_SUPERBLOCK_OFFSET, 0x200);
+ if (js == NULL)
+ return -1;
+
+ if (memcmp(js->magic, "JFS1", 4) != 0)
+ return -1;
+
+// volume_id_set_label_raw(id, js->label, 16);
+ volume_id_set_label_string(id, js->label, 16);
+ volume_id_set_uuid(id, js->uuid, UUID_DCE);
+
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+// id->type = "jfs";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/linux_raid.c b/release/src/router/busybox/util-linux/volume_id/linux_raid.c
new file mode 100644
index 00000000..cc024692
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/linux_raid.c
@@ -0,0 +1,80 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct mdp_super_block {
+ uint32_t md_magic;
+ uint32_t major_version;
+ uint32_t minor_version;
+ uint32_t patch_version;
+ uint32_t gvalid_words;
+ uint32_t set_uuid0;
+ uint32_t ctime;
+ uint32_t level;
+ uint32_t size;
+ uint32_t nr_disks;
+ uint32_t raid_disks;
+ uint32_t md_minor;
+ uint32_t not_persistent;
+ uint32_t set_uuid1;
+ uint32_t set_uuid2;
+ uint32_t set_uuid3;
+} __attribute__((packed));
+
+#define MD_RESERVED_BYTES 0x10000
+#define MD_MAGIC 0xa92b4efc
+
+int volume_id_probe_linux_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size)
+{
+#define off ((uint64_t)0)
+ uint64_t sboff;
+ uint8_t uuid[16];
+ struct mdp_super_block *mdp;
+
+ dbg("probing at offset 0x%llx, size 0x%llx",
+ (unsigned long long) off, (unsigned long long) size);
+
+ if (size < 0x10000)
+ return -1;
+
+ sboff = (size & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES;
+ mdp = volume_id_get_buffer(id, off + sboff, 0x800);
+ if (mdp == NULL)
+ return -1;
+
+ if (mdp->md_magic != cpu_to_le32(MD_MAGIC))
+ return -1;
+
+ *(uint32_t*)uuid = mdp->set_uuid0;
+ memcpy(&uuid[4], &mdp->set_uuid1, 12);
+ volume_id_set_uuid(id, uuid, UUID_DCE);
+
+// snprintf(id->type_version, sizeof(id->type_version)-1, "%u.%u.%u",
+// le32_to_cpu(mdp->major_version),
+// le32_to_cpu(mdp->minor_version),
+// le32_to_cpu(mdp->patch_version));
+
+ dbg("found raid signature");
+// volume_id_set_usage(id, VOLUME_ID_RAID);
+// id->type = "linux_raid_member";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/linux_swap.c b/release/src/router/busybox/util-linux/volume_id/linux_swap.c
new file mode 100644
index 00000000..c9b62e9b
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/linux_swap.c
@@ -0,0 +1,74 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct swap_header_v1_2 {
+ uint8_t bootbits[1024];
+ uint32_t version;
+ uint32_t last_page;
+ uint32_t nr_badpages;
+ uint8_t uuid[16];
+ uint8_t volume_name[16];
+} __attribute__((__packed__));
+
+#define LARGEST_PAGESIZE 0x4000
+
+int volume_id_probe_linux_swap(struct volume_id *id /*,uint64_t off*/)
+{
+#define off ((uint64_t)0)
+ struct swap_header_v1_2 *sw;
+ const uint8_t *buf;
+ unsigned page;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ /* the swap signature is at the end of the PAGE_SIZE */
+ for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) {
+ buf = volume_id_get_buffer(id, off + page-10, 10);
+ if (buf == NULL)
+ return -1;
+
+ if (memcmp(buf, "SWAP-SPACE", 10) == 0) {
+// id->type_version[0] = '1';
+// id->type_version[1] = '\0';
+ goto found;
+ }
+
+ if (memcmp(buf, "SWAPSPACE2", 10) == 0) {
+ sw = volume_id_get_buffer(id, off, sizeof(struct swap_header_v1_2));
+ if (sw == NULL)
+ return -1;
+// id->type_version[0] = '2';
+// id->type_version[1] = '\0';
+// volume_id_set_label_raw(id, sw->volume_name, 16);
+ volume_id_set_label_string(id, sw->volume_name, 16);
+ volume_id_set_uuid(id, sw->uuid, UUID_DCE);
+ goto found;
+ }
+ }
+ return -1;
+
+found:
+// volume_id_set_usage(id, VOLUME_ID_OTHER);
+// id->type = "swap";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/luks.c b/release/src/router/busybox/util-linux/volume_id/luks.c
new file mode 100644
index 00000000..ebc7d160
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/luks.c
@@ -0,0 +1,100 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 W. Michael Petullo <mike@flyn.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+#define LUKS_MAGIC_L 6
+#define UUID_STRING_L 40
+#define LUKS_CIPHERNAME_L 32
+#define LUKS_CIPHERMODE_L 32
+#define LUKS_HASHSPEC_L 32
+#define LUKS_DIGESTSIZE 20
+#define LUKS_SALTSIZE 32
+#define LUKS_NUMKEYS 8
+
+static const uint8_t LUKS_MAGIC[] = { 'L','U','K','S', 0xba, 0xbe };
+
+struct luks_phdr {
+ uint8_t magic[LUKS_MAGIC_L];
+ uint16_t version;
+ uint8_t cipherName[LUKS_CIPHERNAME_L];
+ uint8_t cipherMode[LUKS_CIPHERMODE_L];
+ uint8_t hashSpec[LUKS_HASHSPEC_L];
+ uint32_t payloadOffset;
+ uint32_t keyBytes;
+ uint8_t mkDigest[LUKS_DIGESTSIZE];
+ uint8_t mkDigestSalt[LUKS_SALTSIZE];
+ uint32_t mkDigestIterations;
+ uint8_t uuid[UUID_STRING_L];
+ struct {
+ uint32_t active;
+ uint32_t passwordIterations;
+ uint8_t passwordSalt[LUKS_SALTSIZE];
+ uint32_t keyMaterialOffset;
+ uint32_t stripes;
+ } keyblock[LUKS_NUMKEYS];
+};
+
+enum {
+ EXPECTED_SIZE_luks_phdr = 0
+ + 1 * LUKS_MAGIC_L
+ + 2
+ + 1 * LUKS_CIPHERNAME_L
+ + 1 * LUKS_CIPHERMODE_L
+ + 1 * LUKS_HASHSPEC_L
+ + 4
+ + 4
+ + 1 * LUKS_DIGESTSIZE
+ + 1 * LUKS_SALTSIZE
+ + 4
+ + 1 * UUID_STRING_L
+ + LUKS_NUMKEYS * (0
+ + 4
+ + 4
+ + 1 * LUKS_SALTSIZE
+ + 4
+ + 4
+ )
+};
+
+struct BUG_bad_size_luks_phdr {
+ char BUG_bad_size_luks_phdr[
+ sizeof(struct luks_phdr) == EXPECTED_SIZE_luks_phdr ?
+ 1 : -1];
+};
+
+int volume_id_probe_luks(struct volume_id *id /*,uint64_t off*/)
+{
+#define off ((uint64_t)0)
+ struct luks_phdr *header;
+
+ header = volume_id_get_buffer(id, off, sizeof(*header));
+ if (header == NULL)
+ return -1;
+
+ if (memcmp(header->magic, LUKS_MAGIC, LUKS_MAGIC_L))
+ return -1;
+
+// volume_id_set_usage(id, VOLUME_ID_CRYPTO);
+ volume_id_set_uuid(id, header->uuid, UUID_DCE_STRING);
+// id->type = "crypto_LUKS";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/ntfs.c b/release/src/router/busybox/util-linux/volume_id/ntfs.c
new file mode 100644
index 00000000..6e8f1dd3
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/ntfs.c
@@ -0,0 +1,194 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct ntfs_super_block {
+ uint8_t jump[3];
+ uint8_t oem_id[8];
+ uint16_t bytes_per_sector;
+ uint8_t sectors_per_cluster;
+ uint16_t reserved_sectors;
+ uint8_t fats;
+ uint16_t root_entries;
+ uint16_t sectors;
+ uint8_t media_type;
+ uint16_t sectors_per_fat;
+ uint16_t sectors_per_track;
+ uint16_t heads;
+ uint32_t hidden_sectors;
+ uint32_t large_sectors;
+ uint16_t unused[2];
+ uint64_t number_of_sectors;
+ uint64_t mft_cluster_location;
+ uint64_t mft_mirror_cluster_location;
+ int8_t cluster_per_mft_record;
+ uint8_t reserved1[3];
+ int8_t cluster_per_index_record;
+ uint8_t reserved2[3];
+ uint8_t volume_serial[8];
+ uint16_t checksum;
+} __attribute__((__packed__));
+
+struct master_file_table_record {
+ uint8_t magic[4];
+ uint16_t usa_ofs;
+ uint16_t usa_count;
+ uint64_t lsn;
+ uint16_t sequence_number;
+ uint16_t link_count;
+ uint16_t attrs_offset;
+ uint16_t flags;
+ uint32_t bytes_in_use;
+ uint32_t bytes_allocated;
+} __attribute__((__packed__));
+
+struct file_attribute {
+ uint32_t type;
+ uint32_t len;
+ uint8_t non_resident;
+ uint8_t name_len;
+ uint16_t name_offset;
+ uint16_t flags;
+ uint16_t instance;
+ uint32_t value_len;
+ uint16_t value_offset;
+} __attribute__((__packed__));
+
+struct volume_info {
+ uint64_t reserved;
+ uint8_t major_ver;
+ uint8_t minor_ver;
+} __attribute__((__packed__));
+
+#define MFT_RECORD_VOLUME 3
+#define MFT_RECORD_ATTR_VOLUME_NAME 0x60
+#define MFT_RECORD_ATTR_VOLUME_INFO 0x70
+#define MFT_RECORD_ATTR_OBJECT_ID 0x40
+#define MFT_RECORD_ATTR_END 0xffffffffu
+
+int volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/)
+{
+#define off ((uint64_t)0)
+ unsigned sector_size;
+ unsigned cluster_size;
+ uint64_t mft_cluster;
+ uint64_t mft_off;
+ unsigned mft_record_size;
+ unsigned attr_type;
+ unsigned attr_off;
+ unsigned attr_len;
+ unsigned val_off;
+ unsigned val_len;
+ struct master_file_table_record *mftr;
+ struct ntfs_super_block *ns;
+ const uint8_t *buf;
+ const uint8_t *val;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ ns = volume_id_get_buffer(id, off, 0x200);
+ if (ns == NULL)
+ return -1;
+
+ if (memcmp(ns->oem_id, "NTFS", 4) != 0)
+ return -1;
+
+ volume_id_set_uuid(id, ns->volume_serial, UUID_NTFS);
+
+ sector_size = le16_to_cpu(ns->bytes_per_sector);
+ cluster_size = ns->sectors_per_cluster * sector_size;
+ mft_cluster = le64_to_cpu(ns->mft_cluster_location);
+ mft_off = mft_cluster * cluster_size;
+
+ if (ns->cluster_per_mft_record < 0)
+ /* size = -log2(mft_record_size); normally 1024 Bytes */
+ mft_record_size = 1 << -ns->cluster_per_mft_record;
+ else
+ mft_record_size = ns->cluster_per_mft_record * cluster_size;
+
+ dbg("sectorsize 0x%x", sector_size);
+ dbg("clustersize 0x%x", cluster_size);
+ dbg("mftcluster %llu", (unsigned long long) mft_cluster);
+ dbg("mftoffset 0x%llx", (unsigned long long) mft_off);
+ dbg("cluster per mft_record %i", ns->cluster_per_mft_record);
+ dbg("mft record size %i", mft_record_size);
+
+ buf = volume_id_get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size),
+ mft_record_size);
+ if (buf == NULL)
+ goto found;
+
+ mftr = (struct master_file_table_record*) buf;
+
+ dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]);
+ if (memcmp(mftr->magic, "FILE", 4) != 0)
+ goto found;
+
+ attr_off = le16_to_cpu(mftr->attrs_offset);
+ dbg("file $Volume's attributes are at offset %i", attr_off);
+
+ while (1) {
+ struct file_attribute *attr;
+
+ attr = (struct file_attribute*) &buf[attr_off];
+ attr_type = le32_to_cpu(attr->type);
+ attr_len = le16_to_cpu(attr->len);
+ val_off = le16_to_cpu(attr->value_offset);
+ val_len = le32_to_cpu(attr->value_len);
+ attr_off += attr_len;
+
+ if (attr_len == 0)
+ break;
+
+ if (attr_off >= mft_record_size)
+ break;
+
+ if (attr_type == MFT_RECORD_ATTR_END)
+ break;
+
+ dbg("found attribute type 0x%x, len %i, at offset %i",
+ attr_type, attr_len, attr_off);
+
+// if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) {
+// struct volume_info *info;
+// dbg("found info, len %i", val_len);
+// info = (struct volume_info*) (((uint8_t *) attr) + val_off);
+// snprintf(id->type_version, sizeof(id->type_version)-1,
+// "%u.%u", info->major_ver, info->minor_ver);
+// }
+
+ if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
+ dbg("found label, len %i", val_len);
+ if (val_len > VOLUME_ID_LABEL_SIZE)
+ val_len = VOLUME_ID_LABEL_SIZE;
+
+ val = ((uint8_t *) attr) + val_off;
+// volume_id_set_label_raw(id, val, val_len);
+ volume_id_set_label_unicode16(id, val, LE, val_len);
+ }
+ }
+
+ found:
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+// id->type = "ntfs";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/ocfs2.c b/release/src/router/busybox/util-linux/volume_id/ocfs2.c
new file mode 100644
index 00000000..8417d91b
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/ocfs2.c
@@ -0,0 +1,106 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) Andre Masella <andre@masella.no-ip.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+/* All these values are taken from ocfs2-tools's ocfs2_fs.h */
+#define OCFS2_VOL_UUID_LEN 16
+#define OCFS2_MAX_VOL_LABEL_LEN 64
+#define OCFS2_SUPERBLOCK_OFFSET 0x2000
+
+
+/* This is the superblock. The OCFS2 header files have structs in structs.
+This is one has been simplified since we only care about the superblock.
+*/
+
+struct ocfs2_super_block {
+ uint8_t i_signature[8]; /* Signature for validation */
+ uint32_t i_generation; /* Generation number */
+ int16_t i_suballoc_slot; /* Slot suballocator this inode belongs to */
+ uint16_t i_suballoc_bit; /* Bit offset in suballocator block group */
+ uint32_t i_reserved0;
+ uint32_t i_clusters; /* Cluster count */
+ uint32_t i_uid; /* Owner UID */
+ uint32_t i_gid; /* Owning GID */
+ uint64_t i_size; /* Size in bytes */
+ uint16_t i_mode; /* File mode */
+ uint16_t i_links_count; /* Links count */
+ uint32_t i_flags; /* File flags */
+ uint64_t i_atime; /* Access time */
+ uint64_t i_ctime; /* Creation time */
+ uint64_t i_mtime; /* Modification time */
+ uint64_t i_dtime; /* Deletion time */
+ uint64_t i_blkno; /* Offset on disk, in blocks */
+ uint64_t i_last_eb_blk; /* Pointer to last extent block */
+ uint32_t i_fs_generation; /* Generation per fs-instance */
+ uint32_t i_atime_nsec;
+ uint32_t i_ctime_nsec;
+ uint32_t i_mtime_nsec;
+ uint64_t i_reserved1[9];
+ uint64_t i_pad1; /* Generic way to refer to this 64bit union */
+ /* Normally there is a union of the different block types, but we only care about the superblock. */
+ uint16_t s_major_rev_level;
+ uint16_t s_minor_rev_level;
+ uint16_t s_mnt_count;
+ int16_t s_max_mnt_count;
+ uint16_t s_state; /* File system state */
+ uint16_t s_errors; /* Behaviour when detecting errors */
+ uint32_t s_checkinterval; /* Max time between checks */
+ uint64_t s_lastcheck; /* Time of last check */
+ uint32_t s_creator_os; /* OS */
+ uint32_t s_feature_compat; /* Compatible feature set */
+ uint32_t s_feature_incompat; /* Incompatible feature set */
+ uint32_t s_feature_ro_compat; /* Readonly-compatible feature set */
+ uint64_t s_root_blkno; /* Offset, in blocks, of root directory dinode */
+ uint64_t s_system_dir_blkno; /* Offset, in blocks, of system directory dinode */
+ uint32_t s_blocksize_bits; /* Blocksize for this fs */
+ uint32_t s_clustersize_bits; /* Clustersize for this fs */
+ uint16_t s_max_slots; /* Max number of simultaneous mounts before tunefs required */
+ uint16_t s_reserved1;
+ uint32_t s_reserved2;
+ uint64_t s_first_cluster_group; /* Block offset of 1st cluster group header */
+ uint8_t s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */
+ uint8_t s_uuid[OCFS2_VOL_UUID_LEN]; /* 128-bit uuid */
+} __attribute__((__packed__));
+
+int volume_id_probe_ocfs2(struct volume_id *id /*,uint64_t off*/)
+{
+#define off ((uint64_t)0)
+ struct ocfs2_super_block *os;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ os = volume_id_get_buffer(id, off + OCFS2_SUPERBLOCK_OFFSET, 0x200);
+ if (os == NULL)
+ return -1;
+
+ if (memcmp(os->i_signature, "OCFSV2", 6) != 0) {
+ return -1;
+ }
+
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+// volume_id_set_label_raw(id, os->s_label, OCFS2_MAX_VOL_LABEL_LEN < VOLUME_ID_LABEL_SIZE ?
+// OCFS2_MAX_VOL_LABEL_LEN : VOLUME_ID_LABEL_SIZE);
+ volume_id_set_label_string(id, os->s_label, OCFS2_MAX_VOL_LABEL_LEN < VOLUME_ID_LABEL_SIZE ?
+ OCFS2_MAX_VOL_LABEL_LEN : VOLUME_ID_LABEL_SIZE);
+ volume_id_set_uuid(id, os->s_uuid, UUID_DCE);
+// id->type = "ocfs2";
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/reiserfs.c b/release/src/router/busybox/util-linux/volume_id/reiserfs.c
new file mode 100644
index 00000000..b8cdc980
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/reiserfs.c
@@ -0,0 +1,113 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2005 Tobias Klauser <tklauser@access.unizh.ch>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct reiserfs_super_block {
+ uint32_t blocks_count;
+ uint32_t free_blocks;
+ uint32_t root_block;
+ uint32_t journal_block;
+ uint32_t journal_dev;
+ uint32_t orig_journal_size;
+ uint32_t dummy2[5];
+ uint16_t blocksize;
+ uint16_t dummy3[3];
+ uint8_t magic[12];
+ uint32_t dummy4[5];
+ uint8_t uuid[16];
+ uint8_t label[16];
+} __attribute__((__packed__));
+
+struct reiser4_super_block {
+ uint8_t magic[16];
+ uint16_t dummy[2];
+ uint8_t uuid[16];
+ uint8_t label[16];
+ uint64_t dummy2;
+} __attribute__((__packed__));
+
+#define REISERFS1_SUPERBLOCK_OFFSET 0x2000
+#define REISERFS_SUPERBLOCK_OFFSET 0x10000
+
+int volume_id_probe_reiserfs(struct volume_id *id /*,uint64_t off*/)
+{
+#define off ((uint64_t)0)
+ struct reiserfs_super_block *rs;
+ struct reiser4_super_block *rs4;
+
+ dbg("reiserfs: probing at offset 0x%llx", (unsigned long long) off);
+
+ rs = volume_id_get_buffer(id, off + REISERFS_SUPERBLOCK_OFFSET, 0x200);
+ if (rs == NULL)
+ return -1;
+
+ if (memcmp(rs->magic, "ReIsErFs", 8) == 0) {
+ dbg("reiserfs: ReIsErFs, no label");
+// strcpy(id->type_version, "3.5");
+ goto found;
+ }
+ if (memcmp(rs->magic, "ReIsEr2Fs", 9) == 0) {
+ dbg("reiserfs: ReIsEr2Fs");
+// strcpy(id->type_version, "3.6");
+ goto found_label;
+ }
+ if (memcmp(rs->magic, "ReIsEr3Fs", 9) == 0) {
+ dbg("reiserfs: ReIsEr3Fs");
+// strcpy(id->type_version, "JR");
+ goto found_label;
+ }
+
+ rs4 = (struct reiser4_super_block *) rs;
+ if (memcmp(rs4->magic, "ReIsEr4", 7) == 0) {
+// strcpy(id->type_version, "4");
+// volume_id_set_label_raw(id, rs4->label, 16);
+ volume_id_set_label_string(id, rs4->label, 16);
+ volume_id_set_uuid(id, rs4->uuid, UUID_DCE);
+ dbg("reiserfs: ReIsEr4, label '%s' uuid '%s'", id->label, id->uuid);
+ goto found;
+ }
+
+ rs = volume_id_get_buffer(id, off + REISERFS1_SUPERBLOCK_OFFSET, 0x200);
+ if (rs == NULL)
+ return -1;
+
+ if (memcmp(rs->magic, "ReIsErFs", 8) == 0) {
+ dbg("reiserfs: ReIsErFs, no label");
+// strcpy(id->type_version, "3.5");
+ goto found;
+ }
+
+ dbg("reiserfs: no signature found");
+ return -1;
+
+ found_label:
+// volume_id_set_label_raw(id, rs->label, 16);
+ volume_id_set_label_string(id, rs->label, 16);
+ volume_id_set_uuid(id, rs->uuid, UUID_DCE);
+ dbg("reiserfs: label '%s' uuid '%s'", id->label, id->uuid);
+
+ found:
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+// id->type = "reiserfs";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/romfs.c b/release/src/router/busybox/util-linux/volume_id/romfs.c
new file mode 100644
index 00000000..2c061bdf
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/romfs.c
@@ -0,0 +1,55 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct romfs_super {
+ uint8_t magic[8];
+ uint32_t size;
+ uint32_t checksum;
+ uint8_t name[0];
+} __attribute__((__packed__));
+
+int volume_id_probe_romfs(struct volume_id *id /*,uint64_t off*/)
+{
+#define off ((uint64_t)0)
+ struct romfs_super *rfs;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ rfs = volume_id_get_buffer(id, off, 0x200);
+ if (rfs == NULL)
+ return -1;
+
+ if (memcmp(rfs->magic, "-rom1fs-", 4) == 0) {
+ size_t len = strlen((char *)rfs->name);
+
+ if (len) {
+// volume_id_set_label_raw(id, rfs->name, len);
+ volume_id_set_label_string(id, rfs->name, len);
+ }
+
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+// id->type = "romfs";
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/sysv.c b/release/src/router/busybox/util-linux/volume_id/sysv.c
new file mode 100644
index 00000000..16503325
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/sysv.c
@@ -0,0 +1,126 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+#define SYSV_NICINOD 100
+#define SYSV_NICFREE 50
+
+struct sysv_super
+{
+ uint16_t s_isize;
+ uint16_t s_pad0;
+ uint32_t s_fsize;
+ uint16_t s_nfree;
+ uint16_t s_pad1;
+ uint32_t s_free[SYSV_NICFREE];
+ uint16_t s_ninode;
+ uint16_t s_pad2;
+ uint16_t s_inode[SYSV_NICINOD];
+ uint8_t s_flock;
+ uint8_t s_ilock;
+ uint8_t s_fmod;
+ uint8_t s_ronly;
+ uint32_t s_time;
+ uint16_t s_dinfo[4];
+ uint32_t s_tfree;
+ uint16_t s_tinode;
+ uint16_t s_pad3;
+ uint8_t s_fname[6];
+ uint8_t s_fpack[6];
+ uint32_t s_fill[12];
+ uint32_t s_state;
+ uint32_t s_magic;
+ uint32_t s_type;
+} __attribute__((__packed__));
+
+#define XENIX_NICINOD 100
+#define XENIX_NICFREE 100
+
+struct xenix_super {
+ uint16_t s_isize;
+ uint32_t s_fsize;
+ uint16_t s_nfree;
+ uint32_t s_free[XENIX_NICFREE];
+ uint16_t s_ninode;
+ uint16_t s_inode[XENIX_NICINOD];
+ uint8_t s_flock;
+ uint8_t s_ilock;
+ uint8_t s_fmod;
+ uint8_t s_ronly;
+ uint32_t s_time;
+ uint32_t s_tfree;
+ uint16_t s_tinode;
+ uint16_t s_dinfo[4];
+ uint8_t s_fname[6];
+ uint8_t s_fpack[6];
+ uint8_t s_clean;
+ uint8_t s_fill[371];
+ uint32_t s_magic;
+ uint32_t s_type;
+} __attribute__((__packed__));
+
+#define SYSV_SUPERBLOCK_BLOCK 0x01
+#define SYSV_MAGIC 0xfd187e20
+#define XENIX_SUPERBLOCK_BLOCK 0x18
+#define XENIX_MAGIC 0x2b5544
+#define SYSV_MAX_BLOCKSIZE 0x800
+
+int volume_id_probe_sysv(struct volume_id *id /*,uint64_t off*/)
+{
+#define off ((uint64_t)0)
+ struct sysv_super *vs;
+ struct xenix_super *xs;
+ unsigned boff;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ for (boff = 0x200; boff <= SYSV_MAX_BLOCKSIZE; boff <<= 1) {
+ vs = volume_id_get_buffer(id, off + (boff * SYSV_SUPERBLOCK_BLOCK), 0x200);
+ if (vs == NULL)
+ return -1;
+
+ if (vs->s_magic == cpu_to_le32(SYSV_MAGIC) || vs->s_magic == cpu_to_be32(SYSV_MAGIC)) {
+// volume_id_set_label_raw(id, vs->s_fname, 6);
+ volume_id_set_label_string(id, vs->s_fname, 6);
+// id->type = "sysv";
+ goto found;
+ }
+ }
+
+ for (boff = 0x200; boff <= SYSV_MAX_BLOCKSIZE; boff <<= 1) {
+ xs = volume_id_get_buffer(id, off + (boff + XENIX_SUPERBLOCK_BLOCK), 0x200);
+ if (xs == NULL)
+ return -1;
+
+ if (xs->s_magic == cpu_to_le32(XENIX_MAGIC) || xs->s_magic == cpu_to_be32(XENIX_MAGIC)) {
+// volume_id_set_label_raw(id, xs->s_fname, 6);
+ volume_id_set_label_string(id, xs->s_fname, 6);
+// id->type = "xenix";
+ goto found;
+ }
+ }
+
+ return -1;
+
+ found:
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/udf.c b/release/src/router/busybox/util-linux/volume_id/udf.c
new file mode 100644
index 00000000..e272e192
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/udf.c
@@ -0,0 +1,173 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct volume_descriptor {
+ struct descriptor_tag {
+ uint16_t id;
+ uint16_t version;
+ uint8_t checksum;
+ uint8_t reserved;
+ uint16_t serial;
+ uint16_t crc;
+ uint16_t crc_len;
+ uint32_t location;
+ } __attribute__((__packed__)) tag;
+ union {
+ struct anchor_descriptor {
+ uint32_t length;
+ uint32_t location;
+ } __attribute__((__packed__)) anchor;
+ struct primary_descriptor {
+ uint32_t seq_num;
+ uint32_t desc_num;
+ struct dstring {
+ uint8_t clen;
+ uint8_t c[31];
+ } __attribute__((__packed__)) ident;
+ } __attribute__((__packed__)) primary;
+ } __attribute__((__packed__)) type;
+} __attribute__((__packed__));
+
+struct volume_structure_descriptor {
+ uint8_t type;
+ uint8_t id[5];
+ uint8_t version;
+} __attribute__((__packed__));
+
+#define UDF_VSD_OFFSET 0x8000
+
+int volume_id_probe_udf(struct volume_id *id /*,uint64_t off*/)
+{
+#define off ((uint64_t)0)
+ struct volume_descriptor *vd;
+ struct volume_structure_descriptor *vsd;
+ unsigned bs;
+ unsigned b;
+ unsigned type;
+ unsigned count;
+ unsigned loc;
+ unsigned clen;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ vsd = volume_id_get_buffer(id, off + UDF_VSD_OFFSET, 0x200);
+ if (vsd == NULL)
+ return -1;
+
+ if (memcmp(vsd->id, "NSR02", 5) == 0)
+ goto blocksize;
+ if (memcmp(vsd->id, "NSR03", 5) == 0)
+ goto blocksize;
+ if (memcmp(vsd->id, "BEA01", 5) == 0)
+ goto blocksize;
+ if (memcmp(vsd->id, "BOOT2", 5) == 0)
+ goto blocksize;
+ if (memcmp(vsd->id, "CD001", 5) == 0)
+ goto blocksize;
+ if (memcmp(vsd->id, "CDW02", 5) == 0)
+ goto blocksize;
+ if (memcmp(vsd->id, "TEA03", 5) == 0)
+ goto blocksize;
+ return -1;
+
+blocksize:
+ /* search the next VSD to get the logical block size of the volume */
+ for (bs = 0x800; bs < 0x8000; bs += 0x800) {
+ vsd = volume_id_get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800);
+ if (vsd == NULL)
+ return -1;
+ dbg("test for blocksize: 0x%x", bs);
+ if (vsd->id[0] != '\0')
+ goto nsr;
+ }
+ return -1;
+
+nsr:
+ /* search the list of VSDs for a NSR descriptor */
+ for (b = 0; b < 64; b++) {
+ vsd = volume_id_get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800);
+ if (vsd == NULL)
+ return -1;
+
+ dbg("vsd: %c%c%c%c%c",
+ vsd->id[0], vsd->id[1], vsd->id[2], vsd->id[3], vsd->id[4]);
+
+ if (vsd->id[0] == '\0')
+ return -1;
+ if (memcmp(vsd->id, "NSR02", 5) == 0)
+ goto anchor;
+ if (memcmp(vsd->id, "NSR03", 5) == 0)
+ goto anchor;
+ }
+ return -1;
+
+anchor:
+ /* read anchor volume descriptor */
+ vd = volume_id_get_buffer(id, off + (256 * bs), 0x200);
+ if (vd == NULL)
+ return -1;
+
+ type = le16_to_cpu(vd->tag.id);
+ if (type != 2) /* TAG_ID_AVDP */
+ goto found;
+
+ /* get desriptor list address and block count */
+ count = le32_to_cpu(vd->type.anchor.length) / bs;
+ loc = le32_to_cpu(vd->type.anchor.location);
+ dbg("0x%x descriptors starting at logical secor 0x%x", count, loc);
+
+ /* pick the primary descriptor from the list */
+ for (b = 0; b < count; b++) {
+ vd = volume_id_get_buffer(id, off + ((loc + b) * bs), 0x200);
+ if (vd == NULL)
+ return -1;
+
+ type = le16_to_cpu(vd->tag.id);
+ dbg("descriptor type %i", type);
+
+ /* check validity */
+ if (type == 0)
+ goto found;
+ if (le32_to_cpu(vd->tag.location) != loc + b)
+ goto found;
+
+ if (type == 1) /* TAG_ID_PVD */
+ goto pvd;
+ }
+ goto found;
+
+ pvd:
+// volume_id_set_label_raw(id, &(vd->type.primary.ident.clen), 32);
+
+ clen = vd->type.primary.ident.clen;
+ dbg("label string charsize=%i bit", clen);
+ if (clen == 8)
+ volume_id_set_label_string(id, vd->type.primary.ident.c, 31);
+ else if (clen == 16)
+ volume_id_set_label_unicode16(id, vd->type.primary.ident.c, BE, 31);
+
+ found:
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+// id->type = "udf";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/unused_highpoint.c b/release/src/router/busybox/util-linux/volume_id/unused_highpoint.c
new file mode 100644
index 00000000..57c5cadc
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/unused_highpoint.c
@@ -0,0 +1,86 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct hpt37x_meta {
+ uint8_t filler1[32];
+ uint32_t magic;
+} __attribute__((packed));
+
+struct hpt45x_meta {
+ uint32_t magic;
+} __attribute__((packed));
+
+#define HPT37X_CONFIG_OFF 0x1200
+#define HPT37X_MAGIC_OK 0x5a7816f0
+#define HPT37X_MAGIC_BAD 0x5a7816fd
+
+#define HPT45X_MAGIC_OK 0x5a7816f3
+#define HPT45X_MAGIC_BAD 0x5a7816fd
+
+
+int volume_id_probe_highpoint_37x_raid(struct volume_id *id, uint64_t off)
+{
+ struct hpt37x_meta *hpt;
+ uint32_t magic;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ hpt = volume_id_get_buffer(id, off + HPT37X_CONFIG_OFF, 0x200);
+ if (hpt == NULL)
+ return -1;
+
+ magic = hpt->magic;
+ if (magic != cpu_to_le32(HPT37X_MAGIC_OK) && magic != cpu_to_le32(HPT37X_MAGIC_BAD))
+ return -1;
+
+// volume_id_set_usage(id, VOLUME_ID_RAID);
+// id->type = "highpoint_raid_member";
+
+ return 0;
+}
+
+int volume_id_probe_highpoint_45x_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ struct hpt45x_meta *hpt;
+ uint64_t meta_off;
+ uint32_t magic;
+
+ dbg("probing at offset 0x%llx, size 0x%llx",
+ (unsigned long long) off, (unsigned long long) size);
+
+ if (size < 0x10000)
+ return -1;
+
+ meta_off = ((size / 0x200)-11) * 0x200;
+ hpt = volume_id_get_buffer(id, off + meta_off, 0x200);
+ if (hpt == NULL)
+ return -1;
+
+ magic = hpt->magic;
+ if (magic != cpu_to_le32(HPT45X_MAGIC_OK) && magic != cpu_to_le32(HPT45X_MAGIC_BAD))
+ return -1;
+
+// volume_id_set_usage(id, VOLUME_ID_RAID);
+// id->type = "highpoint_raid_member";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/unused_hpfs.c b/release/src/router/busybox/util-linux/volume_id/unused_hpfs.c
new file mode 100644
index 00000000..8b517569
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/unused_hpfs.c
@@ -0,0 +1,49 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct hpfs_super
+{
+ uint8_t magic[4];
+ uint8_t version;
+} __attribute__((__packed__));
+
+#define HPFS_SUPERBLOCK_OFFSET 0x2000
+
+int volume_id_probe_hpfs(struct volume_id *id, uint64_t off)
+{
+ struct hpfs_super *hs;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ hs = volume_id_get_buffer(id, off + HPFS_SUPERBLOCK_OFFSET, 0x200);
+ if (hs == NULL)
+ return -1;
+
+ if (memcmp(hs->magic, "\x49\xe8\x95\xf9", 4) == 0) {
+// sprintf(id->type_version, "%u", hs->version);
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+// id->type = "hpfs";
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/unused_isw_raid.c b/release/src/router/busybox/util-linux/volume_id/unused_isw_raid.c
new file mode 100644
index 00000000..d928245f
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/unused_isw_raid.c
@@ -0,0 +1,58 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct isw_meta {
+ uint8_t sig[32];
+ uint32_t check_sum;
+ uint32_t mpb_size;
+ uint32_t family_num;
+ uint32_t generation_num;
+} __attribute__((packed));
+
+#define ISW_SIGNATURE "Intel Raid ISM Cfg Sig. "
+
+
+int volume_id_probe_intel_software_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ uint64_t meta_off;
+ struct isw_meta *isw;
+
+ dbg("probing at offset 0x%llx, size 0x%llx",
+ (unsigned long long) off, (unsigned long long) size);
+
+ if (size < 0x10000)
+ return -1;
+
+ meta_off = ((size / 0x200)-2) * 0x200;
+ isw = volume_id_get_buffer(id, off + meta_off, 0x200);
+ if (isw == NULL)
+ return -1;
+
+ if (memcmp(isw->sig, ISW_SIGNATURE, sizeof(ISW_SIGNATURE)-1) != 0)
+ return -1;
+
+// volume_id_set_usage(id, VOLUME_ID_RAID);
+// memcpy(id->type_version, &isw->sig[sizeof(ISW_SIGNATURE)-1], 6);
+// id->type = "isw_raid_member";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/unused_lsi_raid.c b/release/src/router/busybox/util-linux/volume_id/unused_lsi_raid.c
new file mode 100644
index 00000000..730a3134
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/unused_lsi_raid.c
@@ -0,0 +1,52 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct lsi_meta {
+ uint8_t sig[6];
+} __attribute__((packed));
+
+#define LSI_SIGNATURE "$XIDE$"
+
+int volume_id_probe_lsi_mega_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ uint64_t meta_off;
+ struct lsi_meta *lsi;
+
+ dbg("probing at offset 0x%llx, size 0x%llx",
+ (unsigned long long) off, (unsigned long long) size);
+
+ if (size < 0x10000)
+ return -1;
+
+ meta_off = ((size / 0x200)-1) * 0x200;
+ lsi = volume_id_get_buffer(id, off + meta_off, 0x200);
+ if (lsi == NULL)
+ return -1;
+
+ if (memcmp(lsi->sig, LSI_SIGNATURE, sizeof(LSI_SIGNATURE)-1) != 0)
+ return -1;
+
+// volume_id_set_usage(id, VOLUME_ID_RAID);
+// id->type = "lsi_mega_raid_member";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/unused_lvm.c b/release/src/router/busybox/util-linux/volume_id/unused_lvm.c
new file mode 100644
index 00000000..caee04ba
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/unused_lvm.c
@@ -0,0 +1,87 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct lvm1_super_block {
+ uint8_t id[2];
+} __attribute__((packed));
+
+struct lvm2_super_block {
+ uint8_t id[8];
+ uint64_t sector_xl;
+ uint32_t crc_xl;
+ uint32_t offset_xl;
+ uint8_t type[8];
+} __attribute__((packed));
+
+#define LVM1_SB_OFF 0x400
+
+int volume_id_probe_lvm1(struct volume_id *id, uint64_t off)
+{
+ struct lvm1_super_block *lvm;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ lvm = volume_id_get_buffer(id, off + LVM1_SB_OFF, 0x800);
+ if (lvm == NULL)
+ return -1;
+
+ if (lvm->id[0] != 'H' || lvm->id[1] != 'M')
+ return -1;
+
+// volume_id_set_usage(id, VOLUME_ID_RAID);
+// id->type = "LVM1_member";
+
+ return 0;
+}
+
+#define LVM2_LABEL_ID "LABELONE"
+#define LVM2LABEL_SCAN_SECTORS 4
+
+int volume_id_probe_lvm2(struct volume_id *id, uint64_t off)
+{
+ const uint8_t *buf;
+ unsigned soff;
+ struct lvm2_super_block *lvm;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ buf = volume_id_get_buffer(id, off, LVM2LABEL_SCAN_SECTORS * 0x200);
+ if (buf == NULL)
+ return -1;
+
+
+ for (soff = 0; soff < LVM2LABEL_SCAN_SECTORS * 0x200; soff += 0x200) {
+ lvm = (struct lvm2_super_block *) &buf[soff];
+
+ if (memcmp(lvm->id, LVM2_LABEL_ID, 8) == 0)
+ goto found;
+ }
+
+ return -1;
+
+ found:
+// memcpy(id->type_version, lvm->type, 8);
+// volume_id_set_usage(id, VOLUME_ID_RAID);
+// id->type = "LVM2_member";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/unused_mac.c b/release/src/router/busybox/util-linux/volume_id/unused_mac.c
new file mode 100644
index 00000000..8eaa1734
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/unused_mac.c
@@ -0,0 +1,123 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct mac_driver_desc {
+ uint8_t signature[2];
+ uint16_t block_size;
+ uint32_t block_count;
+} __attribute__((__packed__));
+
+struct mac_partition {
+ uint8_t signature[2];
+ uint16_t res1;
+ uint32_t map_count;
+ uint32_t start_block;
+ uint32_t block_count;
+ uint8_t name[32];
+ uint8_t type[32];
+} __attribute__((__packed__));
+
+int volume_id_probe_mac_partition_map(struct volume_id *id, uint64_t off)
+{
+ const uint8_t *buf;
+ struct mac_driver_desc *driver;
+ struct mac_partition *part;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ buf = volume_id_get_buffer(id, off, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ part = (struct mac_partition *) buf;
+ if (part->signature[0] == 'P' && part->signature[1] == 'M' /* "PM" */
+ && (memcmp(part->type, "Apple_partition_map", 19) == 0)
+ ) {
+ /* linux creates an own subdevice for the map
+ * just return the type if the drive header is missing */
+// volume_id_set_usage(id, VOLUME_ID_PARTITIONTABLE);
+// id->type = "mac_partition_map";
+ return 0;
+ }
+
+ driver = (struct mac_driver_desc *) buf;
+ if (driver->signature[0] == 'E' && driver->signature[1] == 'R') { /* "ER" */
+ /* we are on a main device, like a CD
+ * just try to probe the first partition from the map */
+ unsigned bsize = be16_to_cpu(driver->block_size);
+ int part_count;
+ int i;
+
+ /* get first entry of partition table */
+ buf = volume_id_get_buffer(id, off + bsize, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ part = (struct mac_partition *) buf;
+ if (part->signature[0] != 'P' || part->signature[1] != 'M') /* not "PM" */
+ return -1;
+
+ part_count = be32_to_cpu(part->map_count);
+ dbg("expecting %d partition entries", part_count);
+
+ if (id->partitions != NULL)
+ free(id->partitions);
+ id->partitions = xzalloc(part_count * sizeof(struct volume_id_partition));
+
+ id->partition_count = part_count;
+
+ for (i = 0; i < part_count; i++) {
+ uint64_t poff;
+ uint64_t plen;
+
+ buf = volume_id_get_buffer(id, off + ((i+1) * bsize), 0x200);
+ if (buf == NULL)
+ return -1;
+
+ part = (struct mac_partition *) buf;
+ if (part->signature[0] != 'P' || part->signature[1] != 'M') /* not "PM" */
+ return -1;
+
+ poff = be32_to_cpu(part->start_block) * bsize;
+ plen = be32_to_cpu(part->block_count) * bsize;
+ dbg("found '%s' partition entry at 0x%llx, len 0x%llx",
+ part->type, (unsigned long long) poff,
+ (unsigned long long) plen);
+
+// id->partitions[i].pt_off = poff;
+// id->partitions[i].pt_len = plen;
+
+// if (memcmp(part->type, "Apple_Free", 10) == 0) {
+// volume_id_set_usage_part(&id->partitions[i], VOLUME_ID_UNUSED);
+// } else if (memcmp(part->type, "Apple_partition_map", 19) == 0) {
+// volume_id_set_usage_part(&id->partitions[i], VOLUME_ID_PARTITIONTABLE);
+// } else {
+// volume_id_set_usage_part(&id->partitions[i], VOLUME_ID_UNPROBED);
+// }
+ }
+// volume_id_set_usage(id, VOLUME_ID_PARTITIONTABLE);
+// id->type = "mac_partition_map";
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/unused_minix.c b/release/src/router/busybox/util-linux/volume_id/unused_minix.c
new file mode 100644
index 00000000..2f520933
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/unused_minix.c
@@ -0,0 +1,75 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+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;
+} __attribute__((__packed__));
+
+#define MINIX_SUPERBLOCK_OFFSET 0x400
+
+int volume_id_probe_minix(struct volume_id *id, uint64_t off)
+{
+ struct minix_super_block *ms;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ ms = volume_id_get_buffer(id, off + MINIX_SUPERBLOCK_OFFSET, 0x200);
+ if (ms == NULL)
+ return -1;
+
+ if (ms->s_magic == cpu_to_le16(0x137f)) {
+// id->type_version[0] = '1';
+ goto found;
+ }
+
+ if (ms->s_magic == cpu_to_le16(0x1387)) {
+// id->type_version[0] = '1';
+ goto found;
+ }
+
+ if (ms->s_magic == cpu_to_le16(0x2468)) {
+// id->type_version[0] = '2';
+ goto found;
+ }
+
+ if (ms->s_magic == cpu_to_le16(0x2478)) {
+// id->type_version[0] = '2';
+ goto found;
+ }
+
+ return -1;
+
+ found:
+// id->type_version[1] = '\0';
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+// id->type = "minix";
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/unused_msdos.c b/release/src/router/busybox/util-linux/volume_id/unused_msdos.c
new file mode 100644
index 00000000..097ee672
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/unused_msdos.c
@@ -0,0 +1,193 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct msdos_partition_entry {
+ uint8_t boot_ind;
+ uint8_t head;
+ uint8_t sector;
+ uint8_t cyl;
+ uint8_t sys_ind;
+ uint8_t end_head;
+ uint8_t end_sector;
+ uint8_t end_cyl;
+ uint32_t start_sect;
+ uint32_t nr_sects;
+} __attribute__((packed));
+
+#define MSDOS_PARTTABLE_OFFSET 0x1be
+#define MSDOS_SIG_OFF 0x1fe
+#define BSIZE 0x200
+#define DOS_EXTENDED_PARTITION 0x05
+#define LINUX_EXTENDED_PARTITION 0x85
+#define WIN98_EXTENDED_PARTITION 0x0f
+#define LINUX_RAID_PARTITION 0xfd
+#define is_extended(type) \
+ (type == DOS_EXTENDED_PARTITION || \
+ type == WIN98_EXTENDED_PARTITION || \
+ type == LINUX_EXTENDED_PARTITION)
+#define is_raid(type) \
+ (type == LINUX_RAID_PARTITION)
+
+int volume_id_probe_msdos_part_table(struct volume_id *id, uint64_t off)
+{
+ const uint8_t *buf;
+ int i;
+ uint64_t poff;
+ uint64_t plen;
+ uint64_t extended = 0;
+ uint64_t current;
+ uint64_t next;
+ int limit;
+ int empty = 1;
+ struct msdos_partition_entry *part;
+ struct volume_id_partition *p;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ buf = volume_id_get_buffer(id, off, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ if (buf[MSDOS_SIG_OFF] != 0x55 || buf[MSDOS_SIG_OFF + 1] != 0xaa)
+ return -1;
+
+ /* check flags on all entries for a valid partition table */
+ part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
+ for (i = 0; i < 4; i++) {
+ if (part[i].boot_ind != 0 &&
+ part[i].boot_ind != 0x80)
+ return -1;
+
+ if (part[i].nr_sects != 0)
+ empty = 0;
+ }
+ if (empty == 1)
+ return -1;
+
+ if (id->partitions != NULL)
+ free(id->partitions);
+ id->partitions = xzalloc(VOLUME_ID_PARTITIONS_MAX *
+ sizeof(struct volume_id_partition));
+
+ for (i = 0; i < 4; i++) {
+ poff = (uint64_t) le32_to_cpu(part[i].start_sect) * BSIZE;
+ plen = (uint64_t) le32_to_cpu(part[i].nr_sects) * BSIZE;
+
+ if (plen == 0)
+ continue;
+
+ p = &id->partitions[i];
+
+// p->pt_type_raw = part[i].sys_ind;
+
+ if (is_extended(part[i].sys_ind)) {
+ dbg("found extended partition at 0x%llx", (unsigned long long) poff);
+// volume_id_set_usage_part(p, VOLUME_ID_PARTITIONTABLE);
+// p->type = "msdos_extended_partition";
+ if (extended == 0)
+ extended = off + poff;
+ } else {
+ dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
+ part[i].sys_ind, (unsigned long long) poff, (unsigned long long) plen);
+
+// if (is_raid(part[i].sys_ind))
+// volume_id_set_usage_part(p, VOLUME_ID_RAID);
+// else
+// volume_id_set_usage_part(p, VOLUME_ID_UNPROBED);
+ }
+
+// p->pt_off = off + poff;
+// p->pt_len = plen;
+ id->partition_count = i+1;
+ }
+
+ next = extended;
+ current = extended;
+ limit = 50;
+
+ /* follow extended partition chain and add data partitions */
+ while (next != 0) {
+ if (limit-- == 0) {
+ dbg("extended chain limit reached");
+ break;
+ }
+
+ buf = volume_id_get_buffer(id, current, 0x200);
+ if (buf == NULL)
+ break;
+
+ part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
+
+ if (buf[MSDOS_SIG_OFF] != 0x55 || buf[MSDOS_SIG_OFF + 1] != 0xaa)
+ break;
+
+ next = 0;
+
+ for (i = 0; i < 4; i++) {
+ poff = (uint64_t) le32_to_cpu(part[i].start_sect) * BSIZE;
+ plen = (uint64_t) le32_to_cpu(part[i].nr_sects) * BSIZE;
+
+ if (plen == 0)
+ continue;
+
+ if (is_extended(part[i].sys_ind)) {
+ dbg("found extended partition at 0x%llx", (unsigned long long) poff);
+ if (next == 0)
+ next = extended + poff;
+ } else {
+ dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
+ part[i].sys_ind, (unsigned long long) poff, (unsigned long long) plen);
+
+ /* we always start at the 5th entry */
+// while (id->partition_count < 4)
+// volume_id_set_usage_part(&id->partitions[id->partition_count++], VOLUME_ID_UNUSED);
+ if (id->partition_count < 4)
+ id->partition_count = 4;
+
+ p = &id->partitions[id->partition_count];
+
+// if (is_raid(part[i].sys_ind))
+// volume_id_set_usage_part(p, VOLUME_ID_RAID);
+// else
+// volume_id_set_usage_part(p, VOLUME_ID_UNPROBED);
+
+// p->pt_off = current + poff;
+// p->pt_len = plen;
+ id->partition_count++;
+
+// p->pt_type_raw = part[i].sys_ind;
+
+ if (id->partition_count >= VOLUME_ID_PARTITIONS_MAX) {
+ dbg("too many partitions");
+ next = 0;
+ }
+ }
+ }
+
+ current = next;
+ }
+
+// volume_id_set_usage(id, VOLUME_ID_PARTITIONTABLE);
+// id->type = "msdos_partition_table";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/unused_nvidia_raid.c b/release/src/router/busybox/util-linux/volume_id/unused_nvidia_raid.c
new file mode 100644
index 00000000..692aad11
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/unused_nvidia_raid.c
@@ -0,0 +1,56 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct nvidia_meta {
+ uint8_t vendor[8];
+ uint32_t size;
+ uint32_t chksum;
+ uint16_t version;
+} __attribute__((packed));
+
+#define NVIDIA_SIGNATURE "NVIDIA"
+
+int volume_id_probe_nvidia_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ uint64_t meta_off;
+ struct nvidia_meta *nv;
+
+ dbg("probing at offset 0x%llx, size 0x%llx",
+ (unsigned long long) off, (unsigned long long) size);
+
+ if (size < 0x10000)
+ return -1;
+
+ meta_off = ((size / 0x200)-2) * 0x200;
+ nv = volume_id_get_buffer(id, off + meta_off, 0x200);
+ if (nv == NULL)
+ return -1;
+
+ if (memcmp(nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0)
+ return -1;
+
+// volume_id_set_usage(id, VOLUME_ID_RAID);
+// snprintf(id->type_version, sizeof(id->type_version)-1, "%u", le16_to_cpu(nv->version));
+// id->type = "nvidia_raid_member";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/unused_promise_raid.c b/release/src/router/busybox/util-linux/volume_id/unused_promise_raid.c
new file mode 100644
index 00000000..75c6f89d
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/unused_promise_raid.c
@@ -0,0 +1,63 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct promise_meta {
+ uint8_t sig[24];
+} __attribute__((packed));
+
+#define PDC_CONFIG_OFF 0x1200
+#define PDC_SIGNATURE "Promise Technology, Inc."
+
+int volume_id_probe_promise_fasttrack_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ static const unsigned short sectors[] = {
+ 63, 255, 256, 16, 399
+ };
+
+ struct promise_meta *pdc;
+ unsigned i;
+
+ dbg("probing at offset 0x%llx, size 0x%llx",
+ (unsigned long long) off, (unsigned long long) size);
+
+ if (size < 0x40000)
+ return -1;
+
+ for (i = 0; i < ARRAY_SIZE(sectors); i++) {
+ uint64_t meta_off;
+
+ meta_off = ((size / 0x200) - sectors[i]) * 0x200;
+ pdc = volume_id_get_buffer(id, off + meta_off, 0x200);
+ if (pdc == NULL)
+ return -1;
+
+ if (memcmp(pdc->sig, PDC_SIGNATURE, sizeof(PDC_SIGNATURE)-1) == 0)
+ goto found;
+ }
+ return -1;
+
+ found:
+// volume_id_set_usage(id, VOLUME_ID_RAID);
+// id->type = "promise_fasttrack_raid_member";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/unused_silicon_raid.c b/release/src/router/busybox/util-linux/volume_id/unused_silicon_raid.c
new file mode 100644
index 00000000..51431124
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/unused_silicon_raid.c
@@ -0,0 +1,69 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct silicon_meta {
+ uint8_t unknown0[0x2E];
+ uint8_t ascii_version[0x36 - 0x2E];
+ uint8_t diskname[0x56 - 0x36];
+ uint8_t unknown1[0x60 - 0x56];
+ uint32_t magic;
+ uint32_t unknown1a[0x6C - 0x64];
+ uint32_t array_sectors_low;
+ uint32_t array_sectors_high;
+ uint8_t unknown2[0x78 - 0x74];
+ uint32_t thisdisk_sectors;
+ uint8_t unknown3[0x100 - 0x7C];
+ uint8_t unknown4[0x104 - 0x100];
+ uint16_t product_id;
+ uint16_t vendor_id;
+ uint16_t minor_ver;
+ uint16_t major_ver;
+} __attribute__((packed));
+
+#define SILICON_MAGIC 0x2F000000
+
+int volume_id_probe_silicon_medley_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ uint64_t meta_off;
+ struct silicon_meta *sil;
+
+ dbg("probing at offset 0x%llx, size 0x%llx",
+ (unsigned long long) off, (unsigned long long) size);
+
+ if (size < 0x10000)
+ return -1;
+
+ meta_off = ((size / 0x200)-1) * 0x200;
+ sil = volume_id_get_buffer(id, off + meta_off, 0x200);
+ if (sil == NULL)
+ return -1;
+
+ if (sil->magic != cpu_to_le32(SILICON_MAGIC))
+ return -1;
+
+// volume_id_set_usage(id, VOLUME_ID_RAID);
+// snprintf(id->type_version, sizeof(id->type_version)-1, "%u.%u",
+// le16_to_cpu(sil->major_ver), le16_to_cpu(sil->minor_ver));
+// id->type = "silicon_medley_raid_member";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/unused_ufs.c b/release/src/router/busybox/util-linux/volume_id/unused_ufs.c
new file mode 100644
index 00000000..86937585
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/unused_ufs.c
@@ -0,0 +1,206 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct ufs_super_block {
+ uint32_t fs_link;
+ uint32_t fs_rlink;
+ uint32_t fs_sblkno;
+ uint32_t fs_cblkno;
+ uint32_t fs_iblkno;
+ uint32_t fs_dblkno;
+ uint32_t fs_cgoffset;
+ uint32_t fs_cgmask;
+ uint32_t fs_time;
+ uint32_t fs_size;
+ uint32_t fs_dsize;
+ uint32_t fs_ncg;
+ uint32_t fs_bsize;
+ uint32_t fs_fsize;
+ uint32_t fs_frag;
+ uint32_t fs_minfree;
+ uint32_t fs_rotdelay;
+ uint32_t fs_rps;
+ uint32_t fs_bmask;
+ uint32_t fs_fmask;
+ uint32_t fs_bshift;
+ uint32_t fs_fshift;
+ uint32_t fs_maxcontig;
+ uint32_t fs_maxbpg;
+ uint32_t fs_fragshift;
+ uint32_t fs_fsbtodb;
+ uint32_t fs_sbsize;
+ uint32_t fs_csmask;
+ uint32_t fs_csshift;
+ uint32_t fs_nindir;
+ uint32_t fs_inopb;
+ uint32_t fs_nspf;
+ uint32_t fs_optim;
+ uint32_t fs_npsect_state;
+ uint32_t fs_interleave;
+ uint32_t fs_trackskew;
+ uint32_t fs_id[2];
+ uint32_t fs_csaddr;
+ uint32_t fs_cssize;
+ uint32_t fs_cgsize;
+ uint32_t fs_ntrak;
+ uint32_t fs_nsect;
+ uint32_t fs_spc;
+ uint32_t fs_ncyl;
+ uint32_t fs_cpg;
+ uint32_t fs_ipg;
+ uint32_t fs_fpg;
+ struct ufs_csum {
+ uint32_t cs_ndir;
+ uint32_t cs_nbfree;
+ uint32_t cs_nifree;
+ uint32_t cs_nffree;
+ } __attribute__((__packed__)) fs_cstotal;
+ int8_t fs_fmod;
+ int8_t fs_clean;
+ int8_t fs_ronly;
+ int8_t fs_flags;
+ union {
+ struct {
+ int8_t fs_fsmnt[512];
+ uint32_t fs_cgrotor;
+ uint32_t fs_csp[31];
+ uint32_t fs_maxcluster;
+ uint32_t fs_cpc;
+ uint16_t fs_opostbl[16][8];
+ } __attribute__((__packed__)) fs_u1;
+ struct {
+ int8_t fs_fsmnt[468];
+ uint8_t fs_volname[32];
+ uint64_t fs_swuid;
+ int32_t fs_pad;
+ uint32_t fs_cgrotor;
+ uint32_t fs_ocsp[28];
+ uint32_t fs_contigdirs;
+ uint32_t fs_csp;
+ uint32_t fs_maxcluster;
+ uint32_t fs_active;
+ int32_t fs_old_cpc;
+ int32_t fs_maxbsize;
+ int64_t fs_sparecon64[17];
+ int64_t fs_sblockloc;
+ struct ufs2_csum_total {
+ uint64_t cs_ndir;
+ uint64_t cs_nbfree;
+ uint64_t cs_nifree;
+ uint64_t cs_nffree;
+ uint64_t cs_numclusters;
+ uint64_t cs_spare[3];
+ } __attribute__((__packed__)) fs_cstotal;
+ struct ufs_timeval {
+ int32_t tv_sec;
+ int32_t tv_usec;
+ } __attribute__((__packed__)) fs_time;
+ int64_t fs_size;
+ int64_t fs_dsize;
+ uint64_t fs_csaddr;
+ int64_t fs_pendingblocks;
+ int32_t fs_pendinginodes;
+ } __attribute__((__packed__)) fs_u2;
+ } fs_u11;
+ union {
+ struct {
+ int32_t fs_sparecon[53];
+ int32_t fs_reclaim;
+ int32_t fs_sparecon2[1];
+ int32_t fs_state;
+ uint32_t fs_qbmask[2];
+ uint32_t fs_qfmask[2];
+ } __attribute__((__packed__)) fs_sun;
+ struct {
+ int32_t fs_sparecon[53];
+ int32_t fs_reclaim;
+ int32_t fs_sparecon2[1];
+ uint32_t fs_npsect;
+ uint32_t fs_qbmask[2];
+ uint32_t fs_qfmask[2];
+ } __attribute__((__packed__)) fs_sunx86;
+ struct {
+ int32_t fs_sparecon[50];
+ int32_t fs_contigsumsize;
+ int32_t fs_maxsymlinklen;
+ int32_t fs_inodefmt;
+ uint32_t fs_maxfilesize[2];
+ uint32_t fs_qbmask[2];
+ uint32_t fs_qfmask[2];
+ int32_t fs_state;
+ } __attribute__((__packed__)) fs_44;
+ } fs_u2;
+ int32_t fs_postblformat;
+ int32_t fs_nrpos;
+ int32_t fs_postbloff;
+ int32_t fs_rotbloff;
+ uint32_t fs_magic;
+ uint8_t fs_space[1];
+} __attribute__((__packed__));
+
+#define UFS_MAGIC 0x00011954
+#define UFS2_MAGIC 0x19540119
+#define UFS_MAGIC_FEA 0x00195612
+#define UFS_MAGIC_LFN 0x00095014
+
+int volume_id_probe_ufs(struct volume_id *id, uint64_t off)
+{
+ static const short offsets[] = { 0, 8, 64, 256 };
+
+ uint32_t magic;
+ unsigned i;
+ struct ufs_super_block *ufs;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ for (i = 0; i < ARRAY_SIZE(offsets); i++) {
+ ufs = volume_id_get_buffer(id, off + (offsets[i] * 0x400), 0x800);
+ if (ufs == NULL)
+ return -1;
+
+ dbg("offset 0x%x", offsets[i] * 0x400);
+ magic = ufs->fs_magic;
+ if ((magic == cpu_to_be32(UFS_MAGIC))
+ || (magic == cpu_to_be32(UFS2_MAGIC))
+ || (magic == cpu_to_be32(UFS_MAGIC_FEA))
+ || (magic == cpu_to_be32(UFS_MAGIC_LFN))
+ ) {
+ dbg("magic 0x%08x(be)", magic);
+ goto found;
+ }
+ if ((magic == cpu_to_le32(UFS_MAGIC))
+ || (magic == cpu_to_le32(UFS2_MAGIC))
+ || (magic == cpu_to_le32(UFS_MAGIC_FEA))
+ || (magic == cpu_to_le32(UFS_MAGIC_LFN))
+ ) {
+ dbg("magic 0x%08x(le)", magic);
+ goto found;
+ }
+ }
+ return -1;
+
+ found:
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+// id->type = "ufs";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/unused_via_raid.c b/release/src/router/busybox/util-linux/volume_id/unused_via_raid.c
new file mode 100644
index 00000000..43329469
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/unused_via_raid.c
@@ -0,0 +1,68 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct via_meta {
+ uint16_t signature;
+ uint8_t version_number;
+ struct via_array {
+ uint16_t disk_bits;
+ uint8_t disk_array_ex;
+ uint32_t capacity_low;
+ uint32_t capacity_high;
+ uint32_t serial_checksum;
+ } __attribute((packed)) array;
+ uint32_t serial_checksum[8];
+ uint8_t checksum;
+} __attribute__((packed));
+
+#define VIA_SIGNATURE 0xAA55
+
+int volume_id_probe_via_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+ uint64_t meta_off;
+ struct via_meta *via;
+
+ dbg("probing at offset 0x%llx, size 0x%llx",
+ (unsigned long long) off, (unsigned long long) size);
+
+ if (size < 0x10000)
+ return -1;
+
+ meta_off = ((size / 0x200)-1) * 0x200;
+
+ via = volume_id_get_buffer(id, off + meta_off, 0x200);
+ if (via == NULL)
+ return -1;
+
+ if (via->signature != cpu_to_le16(VIA_SIGNATURE))
+ return -1;
+
+ if (via->version_number > 1)
+ return -1;
+
+// volume_id_set_usage(id, VOLUME_ID_RAID);
+// id->type_version[0] = '0' + via->version_number;
+// id->type_version[1] = '\0';
+// id->type = "via_raid_member";
+
+ return 0;
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/util.c b/release/src/router/busybox/util-linux/volume_id/util.c
new file mode 100644
index 00000000..dd75c7ba
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/util.c
@@ -0,0 +1,282 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+void volume_id_set_unicode16(char *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count)
+{
+ unsigned i, j;
+ unsigned c;
+
+ j = 0;
+ for (i = 0; i + 2 <= count; i += 2) {
+ if (endianess == LE)
+ c = (buf[i+1] << 8) | buf[i];
+ else
+ c = (buf[i] << 8) | buf[i+1];
+ if (c == 0) {
+ str[j] = '\0';
+ break;
+ } else if (c < 0x80) {
+ if (j+1 >= len)
+ break;
+ str[j++] = (uint8_t) c;
+ } else if (c < 0x800) {
+ if (j+2 >= len)
+ break;
+ str[j++] = (uint8_t) (0xc0 | (c >> 6));
+ str[j++] = (uint8_t) (0x80 | (c & 0x3f));
+ } else {
+ if (j+3 >= len)
+ break;
+ str[j++] = (uint8_t) (0xe0 | (c >> 12));
+ str[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
+ str[j++] = (uint8_t) (0x80 | (c & 0x3f));
+ }
+ }
+ str[j] = '\0';
+}
+
+#ifdef UNUSED
+static const char *usage_to_string(enum volume_id_usage usage_id)
+{
+ switch (usage_id) {
+ case VOLUME_ID_FILESYSTEM:
+ return "filesystem";
+ case VOLUME_ID_PARTITIONTABLE:
+ return "partitiontable";
+ case VOLUME_ID_OTHER:
+ return "other";
+ case VOLUME_ID_RAID:
+ return "raid";
+ case VOLUME_ID_DISKLABEL:
+ return "disklabel";
+ case VOLUME_ID_CRYPTO:
+ return "crypto";
+ case VOLUME_ID_UNPROBED:
+ return "unprobed";
+ case VOLUME_ID_UNUSED:
+ return "unused";
+ }
+ return NULL;
+}
+
+void volume_id_set_usage_part(struct volume_id_partition *part, enum volume_id_usage usage_id)
+{
+ part->usage_id = usage_id;
+ part->usage = usage_to_string(usage_id);
+}
+
+void volume_id_set_usage(struct volume_id *id, enum volume_id_usage usage_id)
+{
+ id->usage_id = usage_id;
+ id->usage = usage_to_string(usage_id);
+}
+
+void volume_id_set_label_raw(struct volume_id *id, const uint8_t *buf, size_t count)
+{
+ memcpy(id->label_raw, buf, count);
+ id->label_raw_len = count;
+}
+#endif
+
+#ifdef NOT_NEEDED
+static size_t strnlen(const char *s, size_t maxlen)
+{
+ size_t i;
+ if (!maxlen) return 0;
+ if (!s) return 0;
+ for (i = 0; *s && i < maxlen; ++s) ++i;
+ return i;
+}
+#endif
+
+void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count)
+{
+ unsigned i;
+
+ memcpy(id->label, buf, count);
+
+ /* remove trailing whitespace */
+ i = strnlen(id->label, count);
+ while (i--) {
+ if (!isspace(id->label[i]))
+ break;
+ }
+ id->label[i+1] = '\0';
+}
+
+void volume_id_set_label_unicode16(struct volume_id *id, const uint8_t *buf, enum endian endianess, size_t count)
+{
+ volume_id_set_unicode16(id->label, sizeof(id->label), buf, endianess, count);
+}
+
+void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, enum uuid_format format)
+{
+ unsigned i;
+ unsigned count = 0;
+
+ switch (format) {
+ case UUID_DOS:
+ count = 4;
+ break;
+ case UUID_NTFS:
+ case UUID_HFS:
+ count = 8;
+ break;
+ case UUID_DCE:
+ count = 16;
+ break;
+ case UUID_DCE_STRING:
+ /* 36 is ok, id->uuid has one extra byte for NUL */
+ count = VOLUME_ID_UUID_SIZE;
+ break;
+ }
+// memcpy(id->uuid_raw, buf, count);
+// id->uuid_raw_len = count;
+
+ /* if set, create string in the same format, the native platform uses */
+ for (i = 0; i < count; i++)
+ if (buf[i] != 0)
+ goto set;
+ return; /* all bytes are zero, leave it empty ("") */
+
+set:
+ switch (format) {
+ case UUID_DOS:
+ sprintf(id->uuid, "%02X%02X-%02X%02X",
+ buf[3], buf[2], buf[1], buf[0]);
+ break;
+ case UUID_NTFS:
+ sprintf(id->uuid, "%02X%02X%02X%02X%02X%02X%02X%02X",
+ buf[7], buf[6], buf[5], buf[4],
+ buf[3], buf[2], buf[1], buf[0]);
+ break;
+ case UUID_HFS:
+ sprintf(id->uuid, "%02X%02X%02X%02X%02X%02X%02X%02X",
+ buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7]);
+ break;
+ case UUID_DCE:
+ sprintf(id->uuid,
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5],
+ buf[6], buf[7],
+ buf[8], buf[9],
+ buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
+ break;
+ case UUID_DCE_STRING:
+ memcpy(id->uuid, buf, count);
+ id->uuid[count] = '\0';
+ break;
+ }
+}
+
+/* Do not use xlseek here. With it, single corrupted filesystem
+ * may result in attempt to seek past device -> exit.
+ * It's better to ignore such fs and continue. */
+void *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len)
+{
+ uint8_t *dst;
+ unsigned small_off;
+ ssize_t read_len;
+
+ dbg("get buffer off 0x%llx(%llu), len 0x%zx",
+ (unsigned long long) off, (unsigned long long) off, len);
+
+ /* check if requested area fits in superblock buffer */
+ if (off + len <= SB_BUFFER_SIZE
+ /* && off <= SB_BUFFER_SIZE - want this paranoid overflow check? */
+ ) {
+ if (id->sbbuf == NULL) {
+ id->sbbuf = xmalloc(SB_BUFFER_SIZE);
+ }
+ small_off = off;
+ dst = id->sbbuf;
+
+ /* check if we need to read */
+ len += off;
+ if (len <= id->sbbuf_len)
+ goto ret; /* we already have it */
+
+ dbg("read sbbuf len:0x%x", (unsigned) len);
+ id->sbbuf_len = len;
+ off = 0;
+ goto do_read;
+ }
+
+ if (len > SEEK_BUFFER_SIZE) {
+ dbg("seek buffer too small %d", SEEK_BUFFER_SIZE);
+ return NULL;
+ }
+ dst = id->seekbuf;
+
+ /* check if we need to read */
+ if ((off >= id->seekbuf_off)
+ && ((off + len) <= (id->seekbuf_off + id->seekbuf_len))
+ ) {
+ small_off = off - id->seekbuf_off; /* can't overflow */
+ goto ret; /* we already have it */
+ }
+
+ id->seekbuf_off = off;
+ id->seekbuf_len = len;
+ id->seekbuf = xrealloc(id->seekbuf, len);
+ small_off = 0;
+ dst = id->seekbuf;
+ dbg("read seekbuf off:0x%llx len:0x%zx",
+ (unsigned long long) off, len);
+ do_read:
+ if (lseek(id->fd, off, SEEK_SET) != off) {
+ dbg("seek(0x%llx) failed", (unsigned long long) off);
+ goto err;
+ }
+ read_len = full_read(id->fd, dst, len);
+ if (read_len != len) {
+ dbg("requested 0x%x bytes, got 0x%x bytes",
+ (unsigned) len, (unsigned) read_len);
+ err:
+ /* No filesystem can be this tiny. It's most likely
+ * non-associated loop device, empty drive and so on.
+ * Flag it, making it possible to short circuit future
+ * accesses. Rationale:
+ * users complained of slow blkid due to empty floppy drives.
+ */
+ if (off < 64*1024)
+ id->error = 1;
+ /* id->seekbuf_len or id->sbbuf_len is wrong now! Fixing. */
+ volume_id_free_buffer(id);
+ return NULL;
+ }
+ ret:
+ return dst + small_off;
+}
+
+void volume_id_free_buffer(struct volume_id *id)
+{
+ free(id->sbbuf);
+ id->sbbuf = NULL;
+ id->sbbuf_len = 0;
+ free(id->seekbuf);
+ id->seekbuf = NULL;
+ id->seekbuf_len = 0;
+ id->seekbuf_off = 0; /* paranoia */
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/volume_id.c b/release/src/router/busybox/util-linux/volume_id/volume_id.c
new file mode 100644
index 00000000..1acd9059
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/volume_id.c
@@ -0,0 +1,244 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+
+/* Some detection routines do not set label or uuid anyway,
+ * so they are disabled. */
+
+/* Looks for partitions, we don't use it: */
+#define ENABLE_FEATURE_VOLUMEID_MAC 0
+/* #define ENABLE_FEATURE_VOLUMEID_MSDOS 0 - NB: this one
+ * was not properly added to probe table anyway - ??! */
+
+/* None of RAIDs have label or uuid, except LinuxRAID: */
+#define ENABLE_FEATURE_VOLUMEID_HIGHPOINTRAID 0
+#define ENABLE_FEATURE_VOLUMEID_ISWRAID 0
+#define ENABLE_FEATURE_VOLUMEID_LSIRAID 0
+#define ENABLE_FEATURE_VOLUMEID_LVM 0
+#define ENABLE_FEATURE_VOLUMEID_NVIDIARAID 0
+#define ENABLE_FEATURE_VOLUMEID_PROMISERAID 0
+#define ENABLE_FEATURE_VOLUMEID_SILICONRAID 0
+#define ENABLE_FEATURE_VOLUMEID_VIARAID 0
+
+/* These filesystems also have no label or uuid: */
+#define ENABLE_FEATURE_VOLUMEID_MINIX 0
+#define ENABLE_FEATURE_VOLUMEID_HPFS 0
+#define ENABLE_FEATURE_VOLUMEID_UFS 0
+
+
+typedef int (*raid_probe_fptr)(struct volume_id *id, /*uint64_t off,*/ uint64_t size);
+typedef int (*probe_fptr)(struct volume_id *id /*, uint64_t off*/);
+
+static const raid_probe_fptr raid1[] = {
+#if ENABLE_FEATURE_VOLUMEID_LINUXRAID
+ volume_id_probe_linux_raid,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_ISWRAID
+ volume_id_probe_intel_software_raid,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_LSIRAID
+ volume_id_probe_lsi_mega_raid,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_VIARAID
+ volume_id_probe_via_raid,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_SILICONRAID
+ volume_id_probe_silicon_medley_raid,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_NVIDIARAID
+ volume_id_probe_nvidia_raid,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_PROMISERAID
+ volume_id_probe_promise_fasttrack_raid,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_HIGHPOINTRAID
+ volume_id_probe_highpoint_45x_raid,
+#endif
+};
+
+static const probe_fptr raid2[] = {
+#if ENABLE_FEATURE_VOLUMEID_LVM
+ volume_id_probe_lvm1,
+ volume_id_probe_lvm2,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_HIGHPOINTRAID
+ volume_id_probe_highpoint_37x_raid,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_LUKS
+ volume_id_probe_luks,
+#endif
+};
+
+/* signature in the first block, only small buffer needed */
+static const probe_fptr fs1[] = {
+#if ENABLE_FEATURE_VOLUMEID_FAT
+ volume_id_probe_vfat,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_MAC
+ volume_id_probe_mac_partition_map,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_XFS
+ volume_id_probe_xfs,
+#endif
+};
+
+/* fill buffer with maximum */
+static const probe_fptr fs2[] = {
+#if ENABLE_FEATURE_VOLUMEID_LINUXSWAP
+ volume_id_probe_linux_swap,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_EXT
+ volume_id_probe_ext,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_REISERFS
+ volume_id_probe_reiserfs,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_JFS
+ volume_id_probe_jfs,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_UDF
+ volume_id_probe_udf,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_ISO9660
+ volume_id_probe_iso9660,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_HFS
+ volume_id_probe_hfs_hfsplus,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_UFS
+ volume_id_probe_ufs,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_NTFS
+ volume_id_probe_ntfs,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_CRAMFS
+ volume_id_probe_cramfs,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_ROMFS
+ volume_id_probe_romfs,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_HPFS
+ volume_id_probe_hpfs,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_SYSV
+ volume_id_probe_sysv,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_MINIX
+ volume_id_probe_minix,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_OCFS2
+ volume_id_probe_ocfs2,
+#endif
+};
+
+int volume_id_probe_all(struct volume_id *id, /*uint64_t off,*/ uint64_t size)
+{
+ unsigned i;
+
+ /* probe for raid first, cause fs probes may be successful on raid members */
+ if (size) {
+ for (i = 0; i < ARRAY_SIZE(raid1); i++) {
+ if (raid1[i](id, /*off,*/ size) == 0)
+ goto ret;
+ if (id->error)
+ goto ret;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(raid2); i++) {
+ if (raid2[i](id /*,off*/) == 0)
+ goto ret;
+ if (id->error)
+ goto ret;
+ }
+
+ /* signature in the first block, only small buffer needed */
+ for (i = 0; i < ARRAY_SIZE(fs1); i++) {
+ if (fs1[i](id /*,off*/) == 0)
+ goto ret;
+ if (id->error)
+ goto ret;
+ }
+
+ /* fill buffer with maximum */
+ volume_id_get_buffer(id, 0, SB_BUFFER_SIZE);
+
+ for (i = 0; i < ARRAY_SIZE(fs2); i++) {
+ if (fs2[i](id /*,off*/) == 0)
+ goto ret;
+ if (id->error)
+ goto ret;
+ }
+
+ ret:
+ volume_id_free_buffer(id);
+ return (- id->error); /* 0 or -1 */
+
+}
+
+/* open volume by device node */
+struct volume_id *volume_id_open_node(int fd)
+{
+ struct volume_id *id;
+
+ id = xzalloc(sizeof(struct volume_id));
+ id->fd = fd;
+ ///* close fd on device close */
+ //id->fd_close = 1;
+ return id;
+}
+
+#ifdef UNUSED
+/* open volume by major/minor */
+struct volume_id *volume_id_open_dev_t(dev_t devt)
+{
+ struct volume_id *id;
+ char *tmp_node[VOLUME_ID_PATH_MAX];
+
+ tmp_node = xasprintf("/dev/.volume_id-%u-%u-%u",
+ (unsigned)getpid(), (unsigned)major(devt), (unsigned)minor(devt));
+
+ /* create temporary node to open block device */
+ unlink(tmp_node);
+ if (mknod(tmp_node, (S_IFBLK | 0600), devt) != 0)
+ bb_perror_msg_and_die("cannot mknod(%s)", tmp_node);
+
+ id = volume_id_open_node(tmp_node);
+ unlink(tmp_node);
+ free(tmp_node);
+ return id;
+}
+#endif
+
+void free_volume_id(struct volume_id *id)
+{
+ if (id == NULL)
+ return;
+
+ //if (id->fd_close != 0) - always true
+ close(id->fd);
+ volume_id_free_buffer(id);
+#ifdef UNUSED_PARTITION_CODE
+ free(id->partitions);
+#endif
+ free(id);
+}
diff --git a/release/src/router/busybox/util-linux/volume_id/volume_id_internal.h b/release/src/router/busybox/util-linux/volume_id/volume_id_internal.h
new file mode 100644
index 00000000..af58883b
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/volume_id_internal.h
@@ -0,0 +1,227 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "libbb.h"
+#include "volume_id.h"
+
+PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
+
+#define dbg(...) ((void)0)
+/* #define dbg(...) bb_error_msg(__VA_ARGS__) */
+
+/* volume_id.h */
+
+#define VOLUME_ID_VERSION 48
+
+#define VOLUME_ID_LABEL_SIZE 64
+#define VOLUME_ID_UUID_SIZE 36
+#define VOLUME_ID_FORMAT_SIZE 32
+#define VOLUME_ID_PARTITIONS_MAX 256
+
+enum volume_id_usage {
+ VOLUME_ID_UNUSED,
+ VOLUME_ID_UNPROBED,
+ VOLUME_ID_OTHER,
+ VOLUME_ID_FILESYSTEM,
+ VOLUME_ID_PARTITIONTABLE,
+ VOLUME_ID_RAID,
+ VOLUME_ID_DISKLABEL,
+ VOLUME_ID_CRYPTO,
+};
+
+#ifdef UNUSED_PARTITION_CODE
+struct volume_id_partition {
+// const char *type;
+// const char *usage;
+// smallint usage_id;
+// uint8_t pt_type_raw;
+// uint64_t pt_off;
+// uint64_t pt_len;
+};
+#endif
+
+struct volume_id {
+ int fd;
+// int fd_close:1;
+ int error;
+ size_t sbbuf_len;
+ size_t seekbuf_len;
+ uint8_t *sbbuf;
+ uint8_t *seekbuf;
+ uint64_t seekbuf_off;
+#ifdef UNUSED_PARTITION_CODE
+ struct volume_id_partition *partitions;
+ size_t partition_count;
+#endif
+// uint8_t label_raw[VOLUME_ID_LABEL_SIZE];
+// size_t label_raw_len;
+ char label[VOLUME_ID_LABEL_SIZE+1];
+// uint8_t uuid_raw[VOLUME_ID_UUID_SIZE];
+// size_t uuid_raw_len;
+ /* uuid is stored in ASCII (not binary) form here: */
+ char uuid[VOLUME_ID_UUID_SIZE+1];
+// char type_version[VOLUME_ID_FORMAT_SIZE];
+// smallint usage_id;
+// const char *usage;
+// const char *type;
+};
+
+struct volume_id *volume_id_open_node(int fd);
+int volume_id_probe_all(struct volume_id *id, /*uint64_t off,*/ uint64_t size);
+void free_volume_id(struct volume_id *id);
+
+/* util.h */
+
+/* size of superblock buffer, reiserfs block is at 64k */
+#define SB_BUFFER_SIZE 0x11000
+/* size of seek buffer, FAT cluster is 32k max */
+#define SEEK_BUFFER_SIZE 0x10000
+
+#define bswap16(x) (uint16_t) ( \
+ (((uint16_t)(x) & 0x00ffu) << 8) | \
+ (((uint16_t)(x) & 0xff00u) >> 8))
+
+#define bswap32(x) (uint32_t) ( \
+ (((uint32_t)(x) & 0xff000000u) >> 24) | \
+ (((uint32_t)(x) & 0x00ff0000u) >> 8) | \
+ (((uint32_t)(x) & 0x0000ff00u) << 8) | \
+ (((uint32_t)(x) & 0x000000ffu) << 24))
+
+#define bswap64(x) (uint64_t) ( \
+ (((uint64_t)(x) & 0xff00000000000000ull) >> 56) | \
+ (((uint64_t)(x) & 0x00ff000000000000ull) >> 40) | \
+ (((uint64_t)(x) & 0x0000ff0000000000ull) >> 24) | \
+ (((uint64_t)(x) & 0x000000ff00000000ull) >> 8) | \
+ (((uint64_t)(x) & 0x00000000ff000000ull) << 8) | \
+ (((uint64_t)(x) & 0x0000000000ff0000ull) << 24) | \
+ (((uint64_t)(x) & 0x000000000000ff00ull) << 40) | \
+ (((uint64_t)(x) & 0x00000000000000ffull) << 56))
+
+#if BB_LITTLE_ENDIAN
+#define le16_to_cpu(x) (x)
+#define le32_to_cpu(x) (x)
+#define le64_to_cpu(x) (x)
+#define be16_to_cpu(x) bswap16(x)
+#define be32_to_cpu(x) bswap32(x)
+#define cpu_to_le16(x) (x)
+#define cpu_to_le32(x) (x)
+#define cpu_to_be32(x) bswap32(x)
+#else
+#define le16_to_cpu(x) bswap16(x)
+#define le32_to_cpu(x) bswap32(x)
+#define le64_to_cpu(x) bswap64(x)
+#define be16_to_cpu(x) (x)
+#define be32_to_cpu(x) (x)
+#define cpu_to_le16(x) bswap16(x)
+#define cpu_to_le32(x) bswap32(x)
+#define cpu_to_be32(x) (x)
+#endif
+
+enum uuid_format {
+ UUID_DCE_STRING,
+ UUID_DCE,
+ UUID_DOS,
+ UUID_NTFS,
+ UUID_HFS,
+};
+
+enum endian {
+ LE = 0,
+ BE = 1
+};
+
+void volume_id_set_unicode16(char *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count);
+//void volume_id_set_usage(struct volume_id *id, enum volume_id_usage usage_id);
+//void volume_id_set_usage_part(struct volume_id_partition *part, enum volume_id_usage usage_id);
+//void volume_id_set_label_raw(struct volume_id *id, const uint8_t *buf, size_t count);
+void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count);
+void volume_id_set_label_unicode16(struct volume_id *id, const uint8_t *buf, enum endian endianess, size_t count);
+void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, enum uuid_format format);
+void *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len);
+void volume_id_free_buffer(struct volume_id *id);
+
+
+/* Probe routines */
+
+/* RAID */
+
+//int volume_id_probe_highpoint_37x_raid(struct volume_id *id /*,uint64_t off*/);
+//int volume_id_probe_highpoint_45x_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size);
+
+//int volume_id_probe_intel_software_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size);
+
+int volume_id_probe_linux_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size);
+
+//int volume_id_probe_lsi_mega_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size);
+
+//int volume_id_probe_nvidia_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size);
+
+//int volume_id_probe_promise_fasttrack_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size);
+
+//int volume_id_probe_silicon_medley_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size);
+
+//int volume_id_probe_via_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size);
+
+//int volume_id_probe_lvm1(struct volume_id *id /*,uint64_t off*/);
+//int volume_id_probe_lvm2(struct volume_id *id /*,uint64_t off*/);
+
+/* FS */
+
+int volume_id_probe_cramfs(struct volume_id *id /*,uint64_t off*/);
+
+int volume_id_probe_ext(struct volume_id *id /*,uint64_t off*/);
+
+int volume_id_probe_vfat(struct volume_id *id /*,uint64_t off*/);
+
+int volume_id_probe_hfs_hfsplus(struct volume_id *id /*,uint64_t off*/);
+
+//int volume_id_probe_hpfs(struct volume_id *id /*,uint64_t off*/);
+
+int volume_id_probe_iso9660(struct volume_id *id /*,uint64_t off*/);
+
+int volume_id_probe_jfs(struct volume_id *id /*,uint64_t off*/);
+
+int volume_id_probe_linux_swap(struct volume_id *id /*,uint64_t off*/);
+
+int volume_id_probe_luks(struct volume_id *id /*,uint64_t off*/);
+
+//int volume_id_probe_mac_partition_map(struct volume_id *id /*,uint64_t off*/);
+
+//int volume_id_probe_minix(struct volume_id *id /*,uint64_t off*/);
+
+//int volume_id_probe_msdos_part_table(struct volume_id *id /*,uint64_t off*/);
+
+int volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/);
+
+int volume_id_probe_ocfs2(struct volume_id *id /*,uint64_t off*/);
+
+int volume_id_probe_reiserfs(struct volume_id *id /*,uint64_t off*/);
+
+int volume_id_probe_romfs(struct volume_id *id /*,uint64_t off*/);
+
+int volume_id_probe_sysv(struct volume_id *id /*,uint64_t off*/);
+
+int volume_id_probe_udf(struct volume_id *id /*,uint64_t off*/);
+
+//int volume_id_probe_ufs(struct volume_id *id /*,uint64_t off*/);
+
+int volume_id_probe_xfs(struct volume_id *id /*,uint64_t off*/);
+
+POP_SAVED_FUNCTION_VISIBILITY
diff --git a/release/src/router/busybox/util-linux/volume_id/xfs.c b/release/src/router/busybox/util-linux/volume_id/xfs.c
new file mode 100644
index 00000000..646c81d3
--- /dev/null
+++ b/release/src/router/busybox/util-linux/volume_id/xfs.c
@@ -0,0 +1,60 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "volume_id_internal.h"
+
+struct xfs_super_block {
+ uint8_t magic[4];
+ uint32_t blocksize;
+ uint64_t dblocks;
+ uint64_t rblocks;
+ uint32_t dummy1[2];
+ uint8_t uuid[16];
+ uint32_t dummy2[15];
+ uint8_t fname[12];
+ uint32_t dummy3[2];
+ uint64_t icount;
+ uint64_t ifree;
+ uint64_t fdblocks;
+} __attribute__((__packed__));
+
+int volume_id_probe_xfs(struct volume_id *id /*,uint64_t off*/)
+{
+#define off ((uint64_t)0)
+ struct xfs_super_block *xs;
+
+ dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+ xs = volume_id_get_buffer(id, off, 0x200);
+ if (xs == NULL)
+ return -1;
+
+ if (memcmp(xs->magic, "XFSB", 4) != 0)
+ return -1;
+
+// volume_id_set_label_raw(id, xs->fname, 12);
+ volume_id_set_label_string(id, xs->fname, 12);
+ volume_id_set_uuid(id, xs->uuid, UUID_DCE);
+
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+// id->type = "xfs";
+
+ return 0;
+}