[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit
Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/app/busybox/src/util-linux/Config.src b/ap/app/busybox/src/util-linux/Config.src
new file mode 100644
index 0000000..6c1b928
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/Config.src
@@ -0,0 +1,948 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Linux System Utilities"
+
+INSERT
+
+config ACPID
+ bool "acpid"
+ default y
+ select PLATFORM_LINUX
+ 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.
+
+ N.B. acpid relies on run-parts so have the latter installed.
+
+config FEATURE_ACPID_COMPAT
+ bool "Accept and ignore redundant options"
+ default y
+ depends on ACPID
+ help
+ Accept and ignore compatibility options -g -m -s -S -v.
+
+config BLKID
+ bool "blkid"
+ default y
+ select PLATFORM_LINUX
+ select VOLUMEID
+ help
+ Lists labels and UUIDs of all filesystems.
+ WARNING:
+ With all submodules selected, it will add ~8k to busybox.
+
+config FEATURE_BLKID_TYPE
+ bool "Print filesystem type"
+ default n
+ depends on BLKID
+ help
+ Show TYPE="filesystem type"
+
+config DMESG
+ bool "dmesg"
+ default y
+ select PLATFORM_LINUX
+ help
+ dmesg is used to examine or control the kernel ring buffer. When the
+ Linux kernel prints messages to the system log, they are stored in
+ the kernel ring buffer. You can use dmesg to print the kernel's ring
+ buffer, clear the kernel ring buffer, change the size of the kernel
+ ring buffer, and change the priority level at which kernel messages
+ are also logged to the system console. Enable this option if you
+ wish to enable the 'dmesg' utility.
+
+config FEATURE_DMESG_PRETTY
+ bool "Pretty dmesg output"
+ default y
+ depends on DMESG
+ help
+ If you wish to scrub the syslog level from the output, say 'Y' here.
+ The syslog level is a string prefixed to every line with the form
+ "<#>".
+
+ With this option you will see:
+ # dmesg
+ Linux version 2.6.17.4 .....
+ BIOS-provided physical RAM map:
+ BIOS-e820: 0000000000000000 - 000000000009f000 (usable)
+
+ Without this option you will see:
+ # dmesg
+ <5>Linux version 2.6.17.4 .....
+ <6>BIOS-provided physical RAM map:
+ <6> BIOS-e820: 0000000000000000 - 000000000009f000 (usable)
+
+config FBSET
+ bool "fbset"
+ default y
+ select PLATFORM_LINUX
+ help
+ fbset is used to show or change the settings of a Linux frame buffer
+ device. The frame buffer device provides a simple and unique
+ interface to access a graphics display. Enable this option
+ if you wish to enable the 'fbset' utility.
+
+config FEATURE_FBSET_FANCY
+ bool "Turn on extra fbset options"
+ default y
+ depends on FBSET
+ help
+ This option enables extended fbset options, allowing one to set the
+ framebuffer size, color depth, etc. interface to access a graphics
+ display. Enable this option if you wish to enable extended fbset
+ options.
+
+config FEATURE_FBSET_READMODE
+ bool "Turn on fbset readmode support"
+ default y
+ depends on FBSET
+ help
+ This option allows fbset to read the video mode database stored by
+ default as /etc/fb.modes, which can be used to set frame buffer
+ device to pre-defined video modes.
+
+config FDFLUSH
+ bool "fdflush"
+ default y
+ select PLATFORM_LINUX
+ help
+ fdflush is only needed when changing media on slightly-broken
+ removable media drives. It is used to make Linux believe that a
+ hardware disk-change switch has been actuated, which causes Linux to
+ forget anything it has cached from the previous media. If you have
+ such a slightly-broken drive, you will need to run fdflush every time
+ you change a disk. Most people have working hardware and can safely
+ leave this disabled.
+
+config FDFORMAT
+ bool "fdformat"
+ default y
+ select PLATFORM_LINUX
+ help
+ fdformat is used to low-level format a floppy disk.
+
+config FDISK
+ bool "fdisk"
+ default y
+ select PLATFORM_LINUX
+ help
+ The fdisk utility is used to divide hard disks into one or more
+ logical disks, which are generally called partitions. This utility
+ can be used to list and edit the set of partitions or BSD style
+ 'disk slices' that are defined on a hard drive.
+
+config FDISK_SUPPORT_LARGE_DISKS
+ bool "Support over 4GB disks"
+ default y
+ depends on FDISK
+ depends on !LFS # with LFS no special code is needed
+ help
+ Enable this option to support large disks > 4GB.
+
+config FEATURE_FDISK_WRITABLE
+ bool "Write support"
+ default y
+ depends on FDISK
+ help
+ Enabling this option allows you to create or change a partition table
+ and write those changes out to disk. If you leave this option
+ disabled, you will only be able to view the partition table.
+
+config FEATURE_AIX_LABEL
+ bool "Support AIX disklabels"
+ default n
+ depends on FDISK && FEATURE_FDISK_WRITABLE
+ help
+ Enabling this option allows you to create or change AIX disklabels.
+ Most people can safely leave this option disabled.
+
+config FEATURE_SGI_LABEL
+ bool "Support SGI disklabels"
+ default n
+ depends on FDISK && FEATURE_FDISK_WRITABLE
+ help
+ Enabling this option allows you to create or change SGI disklabels.
+ Most people can safely leave this option disabled.
+
+config FEATURE_SUN_LABEL
+ bool "Support SUN disklabels"
+ default n
+ depends on FDISK && FEATURE_FDISK_WRITABLE
+ help
+ Enabling this option allows you to create or change SUN disklabels.
+ Most people can safely leave this option disabled.
+
+config FEATURE_OSF_LABEL
+ bool "Support BSD disklabels"
+ default n
+ depends on FDISK && FEATURE_FDISK_WRITABLE
+ help
+ Enabling this option allows you to create or change BSD disklabels
+ and define and edit BSD disk slices.
+
+config FEATURE_GPT_LABEL
+ bool "Support GPT disklabels"
+ default n
+ depends on FDISK && FEATURE_FDISK_WRITABLE
+ help
+ Enabling this option allows you to view GUID Partition Table
+ disklabels.
+
+config FEATURE_FDISK_ADVANCED
+ bool "Support expert mode"
+ default y
+ depends on FDISK && FEATURE_FDISK_WRITABLE
+ help
+ Enabling this option allows you to do terribly unsafe things like
+ define arbitrary drive geometry, move the beginning of data in a
+ partition, and similarly evil things. Unless you have a very good
+ reason you would be wise to leave this disabled.
+
+config FINDFS
+ bool "findfs"
+ default y
+ select PLATFORM_LINUX
+ 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 FLOCK
+ bool "flock"
+ default y
+ help
+ Manage locks from shell scripts
+
+config FREERAMDISK
+ bool "freeramdisk"
+ default y
+ select PLATFORM_LINUX
+ help
+ Linux allows you to create ramdisks. This utility allows you to
+ delete them and completely free all memory that was used for the
+ ramdisk. For example, if you boot Linux into a ramdisk and later
+ pivot_root, you may want to free the memory that is allocated to the
+ ramdisk. If you have no use for freeing memory from a ramdisk, leave
+ this disabled.
+
+config FSCK_MINIX
+ bool "fsck_minix"
+ default y
+ help
+ The minix filesystem is a nice, small, compact, read-write filesystem
+ with little overhead. It is not a journaling filesystem however and
+ can experience corruption if it is not properly unmounted or if the
+ power goes off in the middle of a write. This utility allows you to
+ check for and attempt to repair any corruption that occurs to a minix
+ filesystem.
+
+config MKFS_EXT2
+ bool "mkfs_ext2"
+ default y
+ select PLATFORM_LINUX
+ help
+ Utility to create EXT2 filesystems.
+
+config MKFS_MINIX
+ bool "mkfs_minix"
+ default y
+ select PLATFORM_LINUX
+ 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.
+
+config FEATURE_MINIX2
+ bool "Support Minix fs v2 (fsck_minix/mkfs_minix)"
+ default y
+ depends on FSCK_MINIX || MKFS_MINIX
+ help
+ If you wish to be able to create version 2 minix filesystems, enable
+ this. If you enabled 'mkfs_minix' then you almost certainly want to
+ be using the version 2 filesystem support.
+
+config MKFS_REISER
+ bool "mkfs_reiser"
+ default n
+ select PLATFORM_LINUX
+ help
+ Utility to create ReiserFS filesystems.
+ Note: this applet needs a lot of testing and polishing.
+
+config MKFS_VFAT
+ bool "mkfs_vfat"
+ default y
+ select PLATFORM_LINUX
+ help
+ Utility to create FAT32 filesystems.
+
+config GETOPT
+ bool "getopt"
+ default y
+ help
+ The getopt utility is used to break up (parse) options in command
+ lines to make it easy to write complex shell scripts that also check
+ for legal (and illegal) options. If you want to write horribly
+ complex shell scripts, or use some horribly complex shell script
+ written by others, this utility may be for you. Most people will
+ wisely leave this disabled.
+
+config FEATURE_GETOPT_LONG
+ bool "Support option -l"
+ default y if LONG_OPTS
+ depends on GETOPT
+ help
+ Enable support for long options (option -l).
+
+config HEXDUMP
+ bool "hexdump"
+ default y
+ 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 FEATURE_HEXDUMP_REVERSE
+ bool "Support -R, reverse of 'hexdump -Cv'"
+ default y
+ 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 y
+ depends on HEXDUMP
+ help
+ hd is an alias to hexdump -C.
+
+config HWCLOCK
+ bool "hwclock"
+ default y
+ select PLATFORM_LINUX
+ help
+ The hwclock utility is used to read and set the hardware clock
+ on a system. This is primarily used to set the current time on
+ shutdown in the hardware clock, so the hardware will keep the
+ correct time when Linux is _not_ running.
+
+config FEATURE_HWCLOCK_LONG_OPTIONS
+ bool "Support long options (--hctosys,...)"
+ default y
+ depends on HWCLOCK && LONG_OPTS
+ help
+ By default, the hwclock utility only uses short options. If you
+ are overly fond of its long options, such as --hctosys, --utc, etc)
+ then enable this option.
+
+config FEATURE_HWCLOCK_ADJTIME_FHS
+ bool "Use FHS /var/lib/hwclock/adjtime"
+ default n # util-linux-ng in Fedora 13 still uses /etc/adjtime
+ 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 y
+ 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 y
+ select PLATFORM_LINUX
+ 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 y
+ select PLATFORM_LINUX
+ help
+ losetup is used to associate or detach a loop device with a regular
+ file or block device, and to query the status of a loop device. This
+ version does not currently support enabling data encryption.
+
+config LSPCI
+ bool "lspci"
+ default y
+ #select PLATFORM_LINUX
+ help
+ lspci is a utility for displaying information about PCI buses in the
+ system and devices connected to them.
+
+ This version uses sysfs (/sys/bus/pci/devices) only.
+
+config LSUSB
+ bool "lsusb"
+ default y
+ #select PLATFORM_LINUX
+ help
+ lsusb is a utility for displaying information about USB buses in the
+ system and devices connected to them.
+
+ This version uses sysfs (/sys/bus/usb/devices) only.
+
+config MKSWAP
+ bool "mkswap"
+ default y
+ help
+ The mkswap utility is used to configure a file or disk partition as
+ Linux swap space. This allows Linux to use the entire file or
+ partition as if it were additional RAM, which can greatly increase
+ the capability of low-memory machines. This additional memory is
+ much slower than real RAM, but can be very helpful at preventing your
+ applications being killed by the Linux out of memory (OOM) killer.
+ Once you have created swap space using 'mkswap' you need to enable
+ the swap space using the 'swapon' utility.
+
+config FEATURE_MKSWAP_UUID
+ bool "UUID support"
+ default y
+ depends on MKSWAP
+ help
+ Generate swap spaces with universally unique identifiers.
+
+config MORE
+ bool "more"
+ default y
+ help
+ more is a simple utility which allows you to read text one screen
+ sized page at a time. If you want to read text that is larger than
+ the screen, and you are using anything faster than a 300 baud modem,
+ you will probably find this utility very helpful. If you don't have
+ any need to reading text files, you can leave this disabled.
+
+config MOUNT
+ bool "mount"
+ default y
+ select PLATFORM_LINUX
+ 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 y
+ depends on MOUNT
+ help
+ Enable support for faking a file system mount.
+
+config FEATURE_MOUNT_VERBOSE
+ bool "Support option -v"
+ default y
+ 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 specifying devices by label or UUID"
+ default y
+ 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.
+ This also enables label or uuid support for swapon.
+
+config FEATURE_MOUNT_NFS
+ bool "Support mounting NFS file systems on Linux < 2.6.23"
+ default n
+ depends on MOUNT
+ select FEATURE_HAVE_RPC
+ select FEATURE_SYSLOG
+ help
+ Enable mounting of NFS file systems on Linux kernels prior
+ to version 2.6.23. Note that in this case mounting of NFS
+ over IPv6 will not be possible.
+
+ Note that this option links in RPC support from libc,
+ which is rather large (~10 kbytes on uclibc).
+
+config FEATURE_MOUNT_CIFS
+ bool "Support mounting CIFS/SMB file systems"
+ default y
+ 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 y
+ select PLATFORM_LINUX
+ help
+ The pivot_root utility swaps the mount points for the root filesystem
+ with some other mounted filesystem. This allows you to do all sorts
+ of wild and crazy things with your Linux system and is far more
+ powerful than 'chroot'.
+
+ Note: This is for initrd in linux 2.4. Under initramfs (introduced
+ in linux 2.6) use switch_root instead.
+
+config RDATE
+ bool "rdate"
+ default y
+ help
+ The rdate utility allows you to synchronize the date and time of your
+ system clock with the date and time of a remote networked system using
+ the RFC868 protocol, which is built into the inetd daemon on most
+ systems.
+
+config RDEV
+ bool "rdev"
+ default y
+ help
+ Print the device node associated with the filesystem mounted at '/'.
+
+config READPROFILE
+ bool "readprofile"
+ default y
+ #select PLATFORM_LINUX
+ help
+ This allows you to parse /proc/profile for basic profiling.
+
+config RTCWAKE
+ bool "rtcwake"
+ default y
+ select PLATFORM_LINUX
+ help
+ Enter a system sleep state until specified wakeup time.
+
+config SCRIPT
+ bool "script"
+ default y
+ help
+ The script makes typescript of terminal session.
+
+config SCRIPTREPLAY
+ bool "scriptreplay"
+ default y
+ help
+ This program replays a typescript, using timing information
+ given by script -t.
+
+config SETARCH
+ bool "setarch"
+ default y
+ select PLATFORM_LINUX
+ 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 y
+ select PLATFORM_LINUX
+ help
+ This option enables both the 'swapon' and the 'swapoff' utilities.
+ Once you have created some swap space using 'mkswap', you also need
+ to enable your swap space with the 'swapon' utility. The 'swapoff'
+ utility is used, typically at system shutdown, to disable any swap
+ space. If you are not using any swap space, you can leave this
+ option disabled.
+
+config FEATURE_SWAPON_PRI
+ bool "Support priority option -p"
+ default y
+ depends on SWAPONOFF
+ help
+ Enable support for setting swap device priority in swapon.
+
+config SWITCH_ROOT
+ bool "switch_root"
+ default y
+ select PLATFORM_LINUX
+ help
+ The switch_root utility is used from initramfs to select a new
+ root device. Under initramfs, you have to use this instead of
+ pivot_root. (Stop reading here if you don't care why.)
+
+ Booting with initramfs extracts a gzipped cpio archive into rootfs
+ (which is a variant of ramfs/tmpfs). Because rootfs can't be moved
+ or unmounted*, pivot_root will not work from initramfs. Instead,
+ switch_root deletes everything out of rootfs (including itself),
+ does a mount --move that overmounts rootfs with the new root, and
+ then execs the specified init program.
+
+ * Because the Linux kernel uses rootfs internally as the starting
+ and ending point for searching through the kernel's doubly linked
+ list of active mount points. That's why.
+
+config UMOUNT
+ bool "umount"
+ default y
+ select PLATFORM_LINUX
+ help
+ When you want to remove a mounted filesystem from its current mount
+ point, for example when you are shutting down the system, the
+ 'umount' utility is the tool to use. If you enabled the 'mount'
+ utility, you almost certainly also want to enable 'umount'.
+
+config FEATURE_UMOUNT_ALL
+ bool "Support option -a"
+ default y
+ depends on UMOUNT
+ help
+ Support -a option to unmount all currently mounted filesystems.
+
+comment "Common options for mount/umount"
+ depends on MOUNT || UMOUNT
+
+config FEATURE_MOUNT_LOOP
+ bool "Support loopback mounts"
+ default y
+ 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_MOUNT_LOOP_CREATE
+ bool "Create new loopback devices if needed"
+ default y
+ depends on FEATURE_MOUNT_LOOP
+ help
+ Linux kernels >= 2.6.24 support unlimited loopback devices. They are
+ allocated for use when trying to use a loop device. The loop device
+ must however exist.
+
+ This feature lets mount to try to create next /dev/loopN device
+ if it does not find a free one.
+
+config FEATURE_MTAB_SUPPORT
+ bool "Support for the old /etc/mtab file"
+ default n
+ 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 writable, 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.
+
+config VOLUMEID
+ bool #No description makes it a hidden option
+ default n
+
+menu "Filesystem/Volume identification"
+ depends on VOLUMEID
+
+config FEATURE_VOLUMEID_EXT
+ bool "Ext filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_BTRFS
+ bool "btrfs filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_REISERFS
+ bool "Reiser filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_FAT
+ bool "fat filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_EXFAT
+ bool "exFAT filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ exFAT (extended FAT) is a proprietary file system designed especially
+ for flash drives. It has many features from NTFS, but with less
+ overhead. exFAT is used on most SDXC cards for consumer electronics.
+
+config FEATURE_VOLUMEID_HFS
+ bool "hfs filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_JFS
+ bool "jfs filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+### config FEATURE_VOLUMEID_UFS
+### bool "ufs filesystem"
+### default y
+### depends on VOLUMEID
+### help
+### TODO
+
+config FEATURE_VOLUMEID_XFS
+ bool "xfs filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_NILFS
+ bool "nilfs filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_NTFS
+ bool "ntfs filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_ISO9660
+ bool "iso9660 filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_UDF
+ bool "udf filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_LUKS
+ bool "luks filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_LINUXSWAP
+ bool "linux swap filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+### config FEATURE_VOLUMEID_LVM
+### bool "lvm"
+### default y
+### depends on VOLUMEID
+### help
+### TODO
+
+config FEATURE_VOLUMEID_CRAMFS
+ bool "cramfs filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+### config FEATURE_VOLUMEID_HPFS
+### bool "hpfs filesystem"
+### default y
+### depends on VOLUMEID
+### help
+### TODO
+
+config FEATURE_VOLUMEID_ROMFS
+ bool "romfs filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+config FEATURE_VOLUMEID_SQUASHFS
+ bool "SquashFS filesystem"
+ default y
+ depends on VOLUMEID && FEATURE_BLKID_TYPE
+ help
+ Squashfs is a compressed read-only filesystem for Linux. Squashfs is
+ intended for general read-only filesystem use and in constrained block
+ device/memory systems (e.g. embedded systems) where low overhead is
+ needed.
+
+config FEATURE_VOLUMEID_SYSV
+ bool "sysv filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+### config FEATURE_VOLUMEID_MINIX
+### bool "minix filesystem"
+### default y
+### depends on VOLUMEID
+### help
+### TODO
+
+### These only detect partition tables - not used (yet?)
+### config FEATURE_VOLUMEID_MAC
+### bool "mac filesystem"
+### default y
+### depends on VOLUMEID
+### help
+### TODO
+###
+### config FEATURE_VOLUMEID_MSDOS
+### bool "msdos filesystem"
+### default y
+### depends on VOLUMEID
+### help
+### TODO
+
+config FEATURE_VOLUMEID_OCFS2
+ bool "ocfs2 filesystem"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+### config FEATURE_VOLUMEID_HIGHPOINTRAID
+### bool "highpoint raid"
+### default y
+### depends on VOLUMEID
+### help
+### TODO
+
+### config FEATURE_VOLUMEID_ISWRAID
+### bool "intel raid"
+### default y
+### depends on VOLUMEID
+### help
+### TODO
+
+### config FEATURE_VOLUMEID_LSIRAID
+### bool "lsi raid"
+### default y
+### depends on VOLUMEID
+### help
+### TODO
+
+### config FEATURE_VOLUMEID_VIARAID
+### bool "via raid"
+### default y
+### depends on VOLUMEID
+### help
+### TODO
+
+### config FEATURE_VOLUMEID_SILICONRAID
+### bool "silicon raid"
+### default y
+### depends on VOLUMEID
+### help
+### TODO
+
+### config FEATURE_VOLUMEID_NVIDIARAID
+### bool "nvidia raid"
+### default y
+### depends on VOLUMEID
+### help
+### TODO
+
+### config FEATURE_VOLUMEID_PROMISERAID
+### bool "promise raid"
+### default y
+### depends on VOLUMEID
+### help
+### TODO
+
+config FEATURE_VOLUMEID_LINUXRAID
+ bool "linuxraid"
+ default y
+ depends on VOLUMEID
+ help
+ TODO
+
+endmenu
+
+endmenu
diff --git a/ap/app/busybox/src/util-linux/Kbuild.src b/ap/app/busybox/src/util-linux/Kbuild.src
new file mode 100644
index 0000000..468fc6b
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/Kbuild.src
@@ -0,0 +1,46 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under GPLv2, see file LICENSE in this source tree.
+
+lib-y:=
+
+INSERT
+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_FLOCK) += flock.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_LSPCI) += lspci.o
+lib-$(CONFIG_LSUSB) += lsusb.o
+lib-$(CONFIG_MKFS_EXT2) += mkfs_ext2.o
+lib-$(CONFIG_MKFS_MINIX) += mkfs_minix.o
+lib-$(CONFIG_MKFS_REISER) += mkfs_reiser.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_SCRIPTREPLAY) += scriptreplay.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/ap/app/busybox/src/util-linux/acpid.c b/ap/app/busybox/src/util-linux/acpid.c
new file mode 100644
index 0000000..38421c2
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/acpid.c
@@ -0,0 +1,358 @@
+/* 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 source tree.
+ */
+
+//usage:#define acpid_trivial_usage
+//usage: "[-df] [-c CONFDIR] [-l LOGFILE] [-a ACTIONFILE] [-M MAPFILE] [-e PROC_EVENT_FILE] [-p PIDFILE]"
+//usage:#define acpid_full_usage "\n\n"
+//usage: "Listen to ACPI events and spawn specific helpers on event arrival\n"
+//usage: "\n -d Log to stderr, not log file (implies -f)"
+//usage: "\n -f Run in foreground"
+//usage: "\n -c DIR Config directory [/etc/acpi]"
+//usage: "\n -e FILE /proc event file [/proc/acpi/event]"
+//usage: "\n -l FILE Log file [/var/log/acpid.log]"
+//usage: "\n -p FILE Pid file [/var/run/acpid.pid]"
+//usage: "\n -a FILE Action file [/etc/acpid.conf]"
+//usage: "\n -M FILE Map file [/etc/acpi.map]"
+//usage: IF_FEATURE_ACPID_COMPAT(
+//usage: "\n\nAccept and ignore compatibility options -g -m -s -S -v"
+//usage: )
+//usage:
+//usage:#define acpid_example_usage
+//usage: "Without -e option, acpid uses all /dev/input/event* files\n"
+//usage: "# acpid\n"
+//usage: "# acpid -l /var/log/my-acpi-log\n"
+//usage: "# acpid -e /proc/acpi/event\n"
+
+#include "libbb.h"
+#include <syslog.h>
+#include <linux/input.h>
+
+#ifndef EV_SW
+# define EV_SW 0x05
+#endif
+#ifndef EV_KEY
+# define EV_KEY 0x01
+#endif
+#ifndef SW_LID
+# define SW_LID 0x00
+#endif
+#ifndef SW_RFKILL_ALL
+# define SW_RFKILL_ALL 0x03
+#endif
+#ifndef KEY_POWER
+# define KEY_POWER 116 /* SC System Power Down */
+#endif
+#ifndef KEY_SLEEP
+# define KEY_SLEEP 142 /* SC System Sleep */
+#endif
+
+enum {
+ OPT_c = (1 << 0),
+ OPT_d = (1 << 1),
+ OPT_e = (1 << 2),
+ OPT_f = (1 << 3),
+ OPT_l = (1 << 4),
+ OPT_a = (1 << 5),
+ OPT_M = (1 << 6),
+ OPT_p = (1 << 7) * ENABLE_FEATURE_PIDFILE,
+};
+
+struct acpi_event {
+ const char *s_type;
+ uint16_t n_type;
+ const char *s_code;
+ uint16_t n_code;
+ uint32_t value;
+ const char *desc;
+};
+
+static const struct acpi_event f_evt_tab[] = {
+ { "EV_KEY", 0x01, "KEY_POWER", 116, 1, "button/power PWRF 00000080" },
+ { "EV_KEY", 0x01, "KEY_POWER", 116, 1, "button/power PWRB 00000080" },
+ { "EV_SW", 0x05, "SW_LID", 0x00, 1, "button/lid LID0 00000080" },
+};
+
+struct acpi_action {
+ const char *key;
+ const char *action;
+};
+
+static const struct acpi_action f_act_tab[] = {
+ { "PWRF", "PWRF/00000080" },
+ { "LID0", "LID/00000080" },
+};
+
+struct globals {
+ struct acpi_action *act_tab;
+ int n_act;
+ struct acpi_event *evt_tab;
+ int n_evt;
+} FIX_ALIASING;
+#define G (*ptr_to_globals)
+#define act_tab (G.act_tab)
+#define n_act (G.n_act )
+#define evt_tab (G.evt_tab)
+#define n_evt (G.n_evt )
+#define INIT_G() do { \
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+} while (0)
+
+/*
+ * 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 & OPT_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);
+}
+
+static const char *find_action(struct input_event *ev, const char *buf)
+{
+ const char *action = NULL;
+ int i;
+
+ // map event
+ for (i = 0; i < n_evt; i++) {
+ if (ev) {
+ if (ev->type == evt_tab[i].n_type && ev->code == evt_tab[i].n_code && ev->value == evt_tab[i].value) {
+ action = evt_tab[i].desc;
+ break;
+ }
+ }
+
+ if (buf) {
+ if (strncmp(buf, evt_tab[i].desc, strlen(buf)) == 0) {
+ action = evt_tab[i].desc;
+ break;
+ }
+ }
+ }
+
+ // get action
+ if (action) {
+ for (i = 0; i < n_act; i++) {
+ if (strstr(action, act_tab[i].key)) {
+ action = act_tab[i].action;
+ break;
+ }
+ }
+ }
+
+ return action;
+}
+
+static void parse_conf_file(const char *filename)
+{
+ parser_t *parser;
+ char *tokens[2];
+
+ parser = config_open2(filename, fopen_for_read);
+
+ if (parser) {
+ while (config_read(parser, tokens, 2, 2, "# \t", PARSE_NORMAL)) {
+ act_tab = xrealloc_vector(act_tab, 1, n_act);
+ act_tab[n_act].key = xstrdup(tokens[0]);
+ act_tab[n_act].action = xstrdup(tokens[1]);
+ n_act++;
+ }
+ config_close(parser);
+ } else {
+ act_tab = (void*)f_act_tab;
+ n_act = ARRAY_SIZE(f_act_tab);
+ }
+}
+
+static void parse_map_file(const char *filename)
+{
+ parser_t *parser;
+ char *tokens[6];
+
+ parser = config_open2(filename, fopen_for_read);
+
+ if (parser) {
+ while (config_read(parser, tokens, 6, 6, "# \t", PARSE_NORMAL)) {
+ evt_tab = xrealloc_vector(evt_tab, 1, n_evt);
+ evt_tab[n_evt].s_type = xstrdup(tokens[0]);
+ evt_tab[n_evt].n_type = xstrtou(tokens[1], 16);
+ evt_tab[n_evt].s_code = xstrdup(tokens[2]);
+ evt_tab[n_evt].n_code = xatou16(tokens[3]);
+ evt_tab[n_evt].value = xatoi_positive(tokens[4]);
+ evt_tab[n_evt].desc = xstrdup(tokens[5]);
+ n_evt++;
+ }
+ config_close(parser);
+ } else {
+ evt_tab = (void*)f_evt_tab;
+ n_evt = ARRAY_SIZE(f_evt_tab);
+ }
+}
+
+/*
+ * acpid [-c conf_dir] [-r conf_file ] [-a map_file ] [-l log_file] [-e proc_event_file]
+ */
+
+int acpid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int acpid_main(int argc UNUSED_PARAM, char **argv)
+{
+ int nfd;
+ int opts;
+ struct pollfd *pfd;
+ const char *opt_dir = "/etc/acpi";
+ const char *opt_input = "/dev/input/event";
+ const char *opt_logfile = "/var/log/acpid.log";
+ const char *opt_action = "/etc/acpid.conf";
+ const char *opt_map = "/etc/acpi.map";
+#if ENABLE_FEATURE_PIDFILE
+ const char *opt_pidfile = CONFIG_PID_FILE_PATH "/acpid.pid";
+#endif
+
+ INIT_G();
+
+ opt_complementary = "df:e--e";
+ opts = getopt32(argv, "c:de:fl:a:M:" IF_FEATURE_PIDFILE("p:") IF_FEATURE_ACPID_COMPAT("g:m:s:S:v"),
+ &opt_dir, &opt_input, &opt_logfile, &opt_action, &opt_map
+ IF_FEATURE_PIDFILE(, &opt_pidfile)
+ IF_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL)
+ );
+
+ if (!(opts & OPT_f)) {
+ /* No -f "Foreground", we go to background */
+ bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
+ }
+
+ if (!(opts & OPT_d)) {
+ /* No -d "Debug", we log to log file.
+ * This includes any output from children.
+ */
+ xmove_fd(xopen(opt_logfile, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
+ xdup2(STDOUT_FILENO, STDERR_FILENO);
+ /* Also, acpid's messages (but not children) will go to syslog too */
+ openlog(applet_name, LOG_PID, LOG_DAEMON);
+ logmode = LOGMODE_SYSLOG | LOGMODE_STDIO;
+ }
+ /* else: -d "Debug", log is not redirected */
+
+ parse_conf_file(opt_action);
+ parse_map_file(opt_map);
+
+ xchdir(opt_dir);
+
+ /* We spawn children but don't wait for them. Prevent zombies: */
+ bb_signals((1 << SIGCHLD), SIG_IGN);
+ // If you enable this, (1) explain why, (2)
+ // make sure while(poll) loop below is still interruptible
+ // by SIGTERM et al:
+ //bb_signals(BB_FATAL_SIGS, record_signo);
+
+ pfd = NULL;
+ nfd = 0;
+ while (1) {
+ int fd;
+ char *dev_event;
+
+ dev_event = xasprintf((opts & OPT_e) ? "%s" : "%s%u", opt_input, nfd);
+ fd = open(dev_event, O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ if (nfd == 0)
+ bb_simple_perror_msg_and_die(dev_event);
+ break;
+ }
+ free(dev_event);
+ pfd = xrealloc_vector(pfd, 1, nfd);
+ pfd[nfd].fd = fd;
+ pfd[nfd].events = POLLIN;
+ nfd++;
+ }
+
+ write_pidfile(opt_pidfile);
+
+ while (safe_poll(pfd, nfd, -1) > 0) {
+ int i;
+ for (i = 0; i < nfd; i++) {
+ const char *event;
+
+ if (!(pfd[i].revents & POLLIN)) {
+ if (pfd[i].revents == 0)
+ continue; /* this fd has nothing */
+
+ /* Likely POLLERR, POLLHUP, POLLNVAL.
+ * Do not listen on this fd anymore.
+ */
+ close(pfd[i].fd);
+ nfd--;
+ for (; i < nfd; i++)
+ pfd[i].fd = pfd[i + 1].fd;
+ break; /* do poll() again */
+ }
+
+ event = NULL;
+ if (option_mask32 & OPT_e) {
+ char *buf;
+ int len;
+
+ buf = xmalloc_reads(pfd[i].fd, NULL);
+ /* buf = "button/power PWRB 00000080 00000000" */
+ len = strlen(buf) - 9;
+ if (len >= 0)
+ buf[len] = '\0';
+ event = find_action(NULL, buf);
+ free(buf);
+ } else {
+ struct input_event ev;
+
+ if (sizeof(ev) != full_read(pfd[i].fd, &ev, sizeof(ev)))
+ continue;
+
+ if (ev.value != 1 && ev.value != 0)
+ continue;
+
+ event = find_action(&ev, NULL);
+ }
+ if (!event)
+ continue;
+ /* spawn event handler */
+ process_event(event);
+ }
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ while (nfd--)
+ close(pfd[nfd].fd);
+ free(pfd);
+ }
+ remove_pidfile(opt_pidfile);
+
+ return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/util-linux/blkid.c b/ap/app/busybox/src/util-linux/blkid.c
new file mode 100644
index 0000000..1bbc803
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/blkid.c
@@ -0,0 +1,31 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Print UUIDs on all filesystems
+ *
+ * Copyright (C) 2008 Denys Vlasenko.
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//usage:#define blkid_trivial_usage
+//usage: "[BLOCKDEV]..."
+//usage:#define blkid_full_usage "\n\n"
+//usage: "Print UUIDs of all filesystems"
+
+#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)
+{
+ int scan_devices = 1;
+
+ while (*++argv) {
+ /* Note: bogus device names don't cause any error messages */
+ add_to_uuid_cache(*argv);
+ scan_devices = 0;
+ }
+
+ display_uuid_cache(scan_devices);
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/blockdev.c b/ap/app/busybox/src/util-linux/blockdev.c
new file mode 100644
index 0000000..e25e529
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/blockdev.c
@@ -0,0 +1,206 @@
+/*
+ * blockdev implementation for busybox
+ *
+ * Copyright (C) 2010 Sergey Naumov <sknaumov@gmail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//applet:IF_BLOCKDEV(APPLET(blockdev, BB_DIR_SBIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o
+
+//config:config BLOCKDEV
+//config: bool "blockdev"
+//config: default y
+//config: help
+//config: Performs some ioctls with block devices.
+
+//usage:#define blockdev_trivial_usage
+//usage: "OPTION BLOCKDEV"
+//usage:#define blockdev_full_usage "\n\n"
+//usage: " --setro Set ro"
+//usage: "\n --setrw Set rw"
+//usage: "\n --getro Get ro"
+//usage: "\n --getss Get sector size"
+//usage: "\n --getbsz Get block size"
+//usage: "\n --setbsz BYTES Set block size"
+//usage: "\n --getsz Get device size in 512-byte sectors"
+/*//usage: "\n --getsize Get device size in sectors (deprecated)"*/
+//usage: "\n --getsize64 Get device size in bytes"
+//usage: "\n --flushbufs Flush buffers"
+//usage: "\n --rereadpt Reread partition table"
+
+
+#include "libbb.h"
+#include <linux/fs.h>
+
+enum {
+ ARG_NONE = 0,
+ ARG_INT = 1,
+ ARG_ULONG = 2,
+ /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */
+ ARG_U64 = 3,
+ ARG_MASK = 3,
+
+ FL_USRARG = 4, /* argument is provided by user */
+ FL_NORESULT = 8,
+ FL_SCALE512 = 16,
+};
+
+struct bdc {
+ uint32_t ioc; /* ioctl code */
+ const char name[sizeof("flushbufs")]; /* "--setfoo" wothout "--" */
+ uint8_t flags;
+ int8_t argval; /* default argument value */
+};
+
+static const struct bdc bdcommands[] = {
+ {
+ .ioc = BLKROSET,
+ .name = "setro",
+ .flags = ARG_INT + FL_NORESULT,
+ .argval = 1,
+ },{
+ .ioc = BLKROSET,
+ .name = "setrw",
+ .flags = ARG_INT + FL_NORESULT,
+ .argval = 0,
+ },{
+ .ioc = BLKROGET,
+ .name = "getro",
+ .flags = ARG_INT,
+ .argval = -1,
+ },{
+ .ioc = BLKSSZGET,
+ .name = "getss",
+ .flags = ARG_INT,
+ .argval = -1,
+ },{
+ .ioc = BLKBSZGET,
+ .name = "getbsz",
+ .flags = ARG_INT,
+ .argval = -1,
+ },{
+ .ioc = BLKBSZSET,
+ .name = "setbsz",
+ .flags = ARG_INT + FL_NORESULT + FL_USRARG,
+ .argval = 0,
+ },{
+ .ioc = BLKGETSIZE64,
+ .name = "getsz",
+ .flags = ARG_U64 + FL_SCALE512,
+ .argval = -1,
+ },{
+ .ioc = BLKGETSIZE,
+ .name = "getsize",
+ .flags = ARG_ULONG,
+ .argval = -1,
+ },{
+ .ioc = BLKGETSIZE64,
+ .name = "getsize64",
+ .flags = ARG_U64,
+ .argval = -1,
+ },{
+ .ioc = BLKFLSBUF,
+ .name = "flushbufs",
+ .flags = ARG_NONE + FL_NORESULT,
+ .argval = 0,
+ },{
+ .ioc = BLKRRPART,
+ .name = "rereadpt",
+ .flags = ARG_NONE + FL_NORESULT,
+ .argval = 0,
+ }
+};
+
+static const struct bdc *find_cmd(const char *s)
+{
+ const struct bdc *bdcmd = bdcommands;
+ if (s[0] == '-' && s[1] == '-') {
+ s += 2;
+ do {
+ if (strcmp(s, bdcmd->name) == 0)
+ return bdcmd;
+ bdcmd++;
+ } while (bdcmd != bdcommands + ARRAY_SIZE(bdcommands));
+ }
+ bb_show_usage();
+}
+
+int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int blockdev_main(int argc UNUSED_PARAM, char **argv)
+{
+ const struct bdc *bdcmd;
+ int fd;
+ uint64_t u64;
+ union {
+ int i;
+ unsigned long lu;
+ uint64_t u64;
+ } ioctl_val_on_stack;
+
+ argv++;
+ if (!argv[0] || !argv[1]) /* must have at least 2 args */
+ bb_show_usage();
+
+ bdcmd = find_cmd(*argv);
+
+ u64 = (int)bdcmd->argval;
+ if (bdcmd->flags & FL_USRARG)
+ u64 = xatoi_positive(*++argv);
+
+ argv++;
+ if (!argv[0] || argv[1])
+ bb_show_usage();
+ fd = xopen(argv[0], O_RDONLY);
+
+ ioctl_val_on_stack.u64 = u64;
+#if BB_BIG_ENDIAN
+ /* Store data properly wrt data size.
+ * (1) It's no-op for little-endian.
+ * (2) it's no-op for 0 and -1. Only --setro uses arg != 0 and != -1,
+ * and it is ARG_INT. --setbsz USER_VAL is also ARG_INT.
+ * Thus, we don't need to handle ARG_ULONG.
+ */
+ switch (bdcmd->flags & ARG_MASK) {
+ case ARG_INT:
+ ioctl_val_on_stack.i = (int)u64;
+ break;
+# if 0 /* unused */
+ case ARG_ULONG:
+ ioctl_val_on_stack.lu = (unsigned long)u64;
+ break;
+# endif
+ }
+#endif
+
+ if (ioctl(fd, bdcmd->ioc, &ioctl_val_on_stack.u64) == -1)
+ bb_simple_perror_msg_and_die(*argv);
+
+ /* Fetch it into register(s) */
+ u64 = ioctl_val_on_stack.u64;
+
+ if (bdcmd->flags & FL_SCALE512)
+ u64 >>= 9;
+
+ /* Zero- or one-extend the value if needed, then print */
+ switch (bdcmd->flags & (ARG_MASK+FL_NORESULT)) {
+ case ARG_INT:
+ /* Smaller code when we use long long
+ * (gcc tail-merges printf call)
+ */
+ printf("%lld\n", (long long)(int)u64);
+ break;
+ case ARG_ULONG:
+ u64 = (unsigned long)u64;
+ /* FALLTHROUGH */
+ case ARG_U64:
+ printf("%llu\n", (unsigned long long)u64);
+ break;
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(fd);
+ return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/util-linux/dmesg.c b/ap/app/busybox/src/util-linux/dmesg.c
new file mode 100644
index 0000000..81ba1c9
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/dmesg.c
@@ -0,0 +1,86 @@
+/* vi: set sw=4 ts=4: */
+/*
+ *
+ * dmesg - display/control kernel ring buffer.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ * Copyright 2006 Bernhard Reutner-Fischer <rep.nop@aon.at>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//usage:#define dmesg_trivial_usage
+//usage: "[-c] [-n LEVEL] [-s SIZE]"
+//usage:#define dmesg_full_usage "\n\n"
+//usage: "Print or control the kernel ring buffer\n"
+//usage: "\n -c Clear ring buffer after printing"
+//usage: "\n -n LEVEL Set console logging level"
+//usage: "\n -s SIZE Buffer size"
+
+#include <sys/klog.h>
+#include "libbb.h"
+
+int dmesg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dmesg_main(int argc UNUSED_PARAM, char **argv)
+{
+ int len, level;
+ char *buf;
+ unsigned opts;
+ enum {
+ OPT_c = 1 << 0,
+ OPT_s = 1 << 1,
+ OPT_n = 1 << 2
+ };
+
+ opt_complementary = "s+:n+"; /* numeric */
+ opts = getopt32(argv, "cs:n:", &len, &level);
+ if (opts & OPT_n) {
+ if (klogctl(8, NULL, (long) level))
+ bb_perror_msg_and_die("klogctl");
+ return EXIT_SUCCESS;
+ }
+
+ if (!(opts & OPT_s))
+ len = klogctl(10, NULL, 0); /* read ring buffer size */
+ if (len < 16*1024)
+ len = 16*1024;
+ if (len > 16*1024*1024)
+ len = 16*1024*1024;
+
+ buf = xmalloc(len);
+ len = klogctl(3 + (opts & OPT_c), buf, len); /* read ring buffer */
+ if (len < 0)
+ bb_perror_msg_and_die("klogctl");
+ if (len == 0)
+ return EXIT_SUCCESS;
+
+
+ if (ENABLE_FEATURE_DMESG_PRETTY) {
+ int last = '\n';
+ int in = 0;
+
+ /* Skip <[0-9]+> at the start of lines */
+ while (1) {
+ if (last == '\n' && buf[in] == '<') {
+ while (buf[in++] != '>' && in < len)
+ ;
+ } else {
+ last = buf[in++];
+ putchar(last);
+ }
+ if (in >= len)
+ break;
+ }
+ /* Make sure we end with a newline */
+ if (last != '\n')
+ bb_putchar('\n');
+ } else {
+ full_write(STDOUT_FILENO, buf, len);
+ if (buf[len-1] != '\n')
+ bb_putchar('\n');
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP) free(buf);
+
+ return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/util-linux/fbset.c b/ap/app/busybox/src/util-linux/fbset.c
new file mode 100644
index 0000000..e9aacce
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/fbset.c
@@ -0,0 +1,535 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini fbset implementation for busybox
+ *
+ * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ *
+ * This is a from-scratch implementation of fbset; but the de facto fbset
+ * implementation was a good reference. fbset (original) is released under
+ * the GPL, and is (c) 1995-1999 by:
+ * Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ */
+
+//usage:#define fbset_trivial_usage
+//usage: "[OPTIONS] [MODE]"
+//usage:#define fbset_full_usage "\n\n"
+//usage: "Show and modify frame buffer settings"
+//usage:
+//usage:#define fbset_example_usage
+//usage: "$ fbset\n"
+//usage: "mode \"1024x768-76\"\n"
+//usage: " # D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz\n"
+//usage: " geometry 1024 768 1024 768 16\n"
+//usage: " timings 12714 128 32 16 4 128 4\n"
+//usage: " accel false\n"
+//usage: " rgba 5/11,6/5,5/0,0/0\n"
+//usage: "endmode\n"
+
+#include "libbb.h"
+
+#define DEFAULTFBDEV FB_0
+#define DEFAULTFBMODE "/etc/fb.modes"
+
+/* Stuff stolen from the kernel's fb.h */
+#define FB_ACTIVATE_ALL 64
+enum {
+ FBIOGET_VSCREENINFO = 0x4600,
+ FBIOPUT_VSCREENINFO = 0x4601
+};
+
+struct fb_bitfield {
+ uint32_t offset; /* beginning of bitfield */
+ uint32_t length; /* length of bitfield */
+ uint32_t msb_right; /* !=0: Most significant bit is right */
+};
+struct fb_var_screeninfo {
+ uint32_t xres; /* visible resolution */
+ uint32_t yres;
+ uint32_t xres_virtual; /* virtual resolution */
+ uint32_t yres_virtual;
+ uint32_t xoffset; /* offset from virtual to visible */
+ uint32_t yoffset; /* resolution */
+
+ uint32_t bits_per_pixel;
+ uint32_t grayscale; /* !=0 Graylevels instead of colors */
+
+ struct fb_bitfield red; /* bitfield in fb mem if true color, */
+ struct fb_bitfield green; /* else only length is significant */
+ struct fb_bitfield blue;
+ struct fb_bitfield transp; /* transparency */
+
+ uint32_t nonstd; /* !=0 Non standard pixel format */
+
+ uint32_t activate; /* see FB_ACTIVATE_x */
+
+ uint32_t height; /* height of picture in mm */
+ uint32_t width; /* width of picture in mm */
+
+ uint32_t accel_flags; /* acceleration flags (hints) */
+
+ /* Timing: All values in pixclocks, except pixclock (of course) */
+ uint32_t pixclock; /* pixel clock in ps (pico seconds) */
+ uint32_t left_margin; /* time from sync to picture */
+ uint32_t right_margin; /* time from picture to sync */
+ uint32_t upper_margin; /* time from sync to picture */
+ uint32_t lower_margin;
+ uint32_t hsync_len; /* length of horizontal sync */
+ uint32_t vsync_len; /* length of vertical sync */
+ uint32_t sync; /* see FB_SYNC_x */
+ uint32_t vmode; /* see FB_VMODE_x */
+ uint32_t reserved[6]; /* Reserved for future compatibility */
+};
+
+static void copy_if_gt0(uint32_t *src, uint32_t *dst, unsigned cnt)
+{
+ do {
+ if ((int32_t) *src > 0)
+ *dst = *src;
+ src++;
+ dst++;
+ } while (--cnt);
+}
+
+static NOINLINE void copy_changed_values(
+ struct fb_var_screeninfo *base,
+ struct fb_var_screeninfo *set)
+{
+ //if ((int32_t) set->xres > 0) base->xres = set->xres;
+ //if ((int32_t) set->yres > 0) base->yres = set->yres;
+ //if ((int32_t) set->xres_virtual > 0) base->xres_virtual = set->xres_virtual;
+ //if ((int32_t) set->yres_virtual > 0) base->yres_virtual = set->yres_virtual;
+ copy_if_gt0(&set->xres, &base->xres, 4);
+
+ if ((int32_t) set->bits_per_pixel > 0) base->bits_per_pixel = set->bits_per_pixel;
+ //copy_if_gt0(&set->bits_per_pixel, &base->bits_per_pixel, 1);
+
+ //if ((int32_t) set->pixclock > 0) base->pixclock = set->pixclock;
+ //if ((int32_t) set->left_margin > 0) base->left_margin = set->left_margin;
+ //if ((int32_t) set->right_margin > 0) base->right_margin = set->right_margin;
+ //if ((int32_t) set->upper_margin > 0) base->upper_margin = set->upper_margin;
+ //if ((int32_t) set->lower_margin > 0) base->lower_margin = set->lower_margin;
+ //if ((int32_t) set->hsync_len > 0) base->hsync_len = set->hsync_len;
+ //if ((int32_t) set->vsync_len > 0) base->vsync_len = set->vsync_len;
+ //if ((int32_t) set->sync > 0) base->sync = set->sync;
+ //if ((int32_t) set->vmode > 0) base->vmode = set->vmode;
+ copy_if_gt0(&set->pixclock, &base->pixclock, 9);
+}
+
+
+enum {
+ CMD_FB = 1,
+ CMD_DB = 2,
+ CMD_GEOMETRY = 3,
+ CMD_TIMING = 4,
+ CMD_ACCEL = 5,
+ CMD_HSYNC = 6,
+ CMD_VSYNC = 7,
+ CMD_LACED = 8,
+ CMD_DOUBLE = 9,
+/* CMD_XCOMPAT = 10, */
+ CMD_ALL = 11,
+ CMD_INFO = 12,
+ CMD_SHOW = 13,
+ CMD_CHANGE = 14,
+
+#if ENABLE_FEATURE_FBSET_FANCY
+ CMD_XRES = 100,
+ CMD_YRES = 101,
+ CMD_VXRES = 102,
+ CMD_VYRES = 103,
+ CMD_DEPTH = 104,
+ CMD_MATCH = 105,
+ CMD_PIXCLOCK = 106,
+ CMD_LEFT = 107,
+ CMD_RIGHT = 108,
+ CMD_UPPER = 109,
+ CMD_LOWER = 110,
+ CMD_HSLEN = 111,
+ CMD_VSLEN = 112,
+ CMD_CSYNC = 113,
+ CMD_GSYNC = 114,
+ CMD_EXTSYNC = 115,
+ CMD_BCAST = 116,
+ CMD_RGBA = 117,
+ CMD_STEP = 118,
+ CMD_MOVE = 119,
+#endif
+};
+
+static const struct cmdoptions_t {
+ const char name[9];
+ const unsigned char param_count;
+ const unsigned char code;
+} g_cmdoptions[] = {
+ /*"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
+};
+
+/* taken from linux/fb.h */
+enum {
+ FB_SYNC_HOR_HIGH_ACT = 1, /* horizontal sync high active */
+ FB_SYNC_VERT_HIGH_ACT = 2, /* vertical sync high active */
+#if ENABLE_FEATURE_FBSET_READMODE
+ FB_VMODE_INTERLACED = 1, /* interlaced */
+ FB_VMODE_DOUBLE = 2, /* double scan */
+ FB_SYNC_EXT = 4, /* external sync */
+ FB_SYNC_COMP_HIGH_ACT = 8, /* composite sync high active */
+#endif
+};
+
+#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;
+}
+
+/* Mode db file contains mode definitions like this:
+ * mode "800x600-48-lace"
+ * # D: 36.00 MHz, H: 33.835 kHz, V: 96.39 Hz
+ * geometry 800 600 800 600 8
+ * timings 27778 56 80 79 11 128 12
+ * laced true
+ * hsync high
+ * vsync high
+ * endmode
+ */
+static int read_mode_db(struct fb_var_screeninfo *base, const char *fn,
+ const char *mode)
+{
+ 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\0rgba\0",
+ token[0]);
+ switch (i) {
+ case 0:
+ if (sizeof(int) == sizeof(base->xres)) {
+ sscanf(p, "%d %d %d %d %d",
+ &base->xres, &base->yres,
+ &base->xres_virtual, &base->yres_virtual,
+ &base->bits_per_pixel);
+ } else {
+ int base_xres, base_yres;
+ int base_xres_virtual, base_yres_virtual;
+ int base_bits_per_pixel;
+ sscanf(p, "%d %d %d %d %d",
+ &base_xres, &base_yres,
+ &base_xres_virtual, &base_yres_virtual,
+ &base_bits_per_pixel);
+ base->xres = base_xres;
+ base->yres = base_yres;
+ base->xres_virtual = base_xres_virtual;
+ base->yres_virtual = base_yres_virtual;
+ base->bits_per_pixel = base_bits_per_pixel;
+ }
+//bb_info_msg("GEO[%s]", p);
+ break;
+ case 1:
+ if (sizeof(int) == sizeof(base->xres)) {
+ 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 {
+ int base_pixclock;
+ int base_left_margin, base_right_margin;
+ int base_upper_margin, base_lower_margin;
+ int base_hsync_len, base_vsync_len;
+ 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);
+ base->pixclock = base_pixclock;
+ base->left_margin = base_left_margin;
+ base->right_margin = base_right_margin;
+ base->upper_margin = base_upper_margin;
+ base->lower_margin = base_lower_margin;
+ base->hsync_len = base_hsync_len;
+ base->vsync_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;
+ case 8: {
+ int red_offset, red_length;
+ int green_offset, green_length;
+ int blue_offset, blue_length;
+ int transp_offset, transp_length;
+
+ sscanf(p, "%d/%d,%d/%d,%d/%d,%d/%d",
+ &red_offset, &red_length,
+ &green_offset, &green_length,
+ &blue_offset, &blue_length,
+ &transp_offset, &transp_length);
+ base->red.offset = red_offset;
+ base->red.length = red_length;
+ base->red.msb_right = 0;
+ base->green.offset = green_offset;
+ base->green.length = green_length;
+ base->green.msb_right = 0;
+ base->blue.offset = blue_offset;
+ base->blue.length = blue_length;
+ base->blue.msb_right = 0;
+ base->transp.offset = transp_offset;
+ base->transp.length = transp_length;
+ base->transp.msb_right = 0;
+ }
+ }
+ }
+ return 0;
+}
+#endif
+
+static NOINLINE void showmode(struct fb_var_screeninfo *v)
+{
+ double drate = 0, hrate = 0, vrate = 0;
+
+ if (v->pixclock) {
+ drate = 1e12 / v->pixclock;
+ hrate = drate / (v->left_margin + v->xres + v->right_margin + v->hsync_len);
+ vrate = hrate / (v->upper_margin + v->yres + v->lower_margin + v->vsync_len);
+ }
+ printf("\nmode \"%ux%u-%u\"\n"
+#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\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);
+}
+
+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 << 3),
+ };
+ struct fb_var_screeninfo var_old, var_set;
+ int fh, i;
+ unsigned options = 0;
+
+ const char *fbdev = DEFAULTFBDEV;
+ const char *modefile = DEFAULTFBMODE;
+ char *thisarg;
+ char *mode = mode; /* for compiler */
+
+ memset(&var_set, 0xff, sizeof(var_set)); /* set all to -1 */
+
+ /* parse cmd args.... why do they have to make things so difficult? */
+ argv++;
+ argc--;
+ for (; argc > 0 && (thisarg = *argv) != NULL; argc--, argv++) {
+ if (thisarg[0] != '-') {
+ if (!ENABLE_FEATURE_FBSET_READMODE || argc != 1)
+ bb_show_usage();
+ mode = thisarg;
+ options |= OPT_READMODE;
+ goto contin;
+ }
+ 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:
+ var_set.xres = xatou32(argv[1]);
+ var_set.yres = xatou32(argv[2]);
+ var_set.xres_virtual = xatou32(argv[3]);
+ var_set.yres_virtual = xatou32(argv[4]);
+ var_set.bits_per_pixel = xatou32(argv[5]);
+ break;
+ case CMD_TIMING:
+ var_set.pixclock = xatou32(argv[1]);
+ var_set.left_margin = xatou32(argv[2]);
+ var_set.right_margin = xatou32(argv[3]);
+ var_set.upper_margin = xatou32(argv[4]);
+ var_set.lower_margin = xatou32(argv[5]);
+ var_set.hsync_len = xatou32(argv[6]);
+ var_set.vsync_len = xatou32(argv[7]);
+ break;
+ case CMD_ACCEL:
+ break;
+ case CMD_HSYNC:
+ var_set.sync |= FB_SYNC_HOR_HIGH_ACT;
+ break;
+ case CMD_VSYNC:
+ var_set.sync |= FB_SYNC_VERT_HIGH_ACT;
+ break;
+#if ENABLE_FEATURE_FBSET_FANCY
+ case CMD_XRES:
+ var_set.xres = xatou32(argv[1]);
+ break;
+ case CMD_YRES:
+ var_set.yres = xatou32(argv[1]);
+ break;
+ case CMD_DEPTH:
+ var_set.bits_per_pixel = xatou32(argv[1]);
+ break;
+#endif
+ }
+ switch (g_cmdoptions[i].code) {
+ case CMD_FB:
+ case CMD_DB:
+ case CMD_ALL:
+ case CMD_SHOW:
+ break;
+ default:
+ /* other commands imply changes */
+ options |= OPT_CHANGE;
+ }
+ argc -= g_cmdoptions[i].param_count;
+ argv += g_cmdoptions[i].param_count;
+ goto contin;
+ }
+ bb_show_usage();
+ contin: ;
+ }
+
+ fh = xopen(fbdev, O_RDONLY);
+ xioctl(fh, FBIOGET_VSCREENINFO, &var_old);
+
+ if (options & OPT_READMODE) {
+#if ENABLE_FEATURE_FBSET_READMODE
+ if (!read_mode_db(&var_old, modefile, mode)) {
+ bb_error_msg_and_die("unknown video mode '%s'", mode);
+ }
+ options |= OPT_CHANGE;
+#endif
+ }
+
+ if (options & OPT_CHANGE) {
+ copy_changed_values(&var_old, &var_set);
+ if (options & OPT_ALL)
+ var_old.activate = FB_ACTIVATE_ALL;
+ xioctl(fh, FBIOPUT_VSCREENINFO, &var_old);
+ }
+
+ if (options == 0 || (options & OPT_SHOW))
+ showmode(&var_old);
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(fh);
+
+ return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/util-linux/fdformat.c b/ap/app/busybox/src/util-linux/fdformat.c
new file mode 100644
index 0000000..b3e918f
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/fdformat.c
@@ -0,0 +1,137 @@
+/* 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 source tree.
+ */
+
+//usage:#define fdformat_trivial_usage
+//usage: "[-n] DEVICE"
+//usage:#define fdformat_full_usage "\n\n"
+//usage: "Format floppy disk\n"
+//usage: "\n -n Don't verify after format"
+
+#include "libbb.h"
+
+
+/* Stuff extracted from linux/fd.h */
+struct floppy_struct {
+ unsigned int size, /* nr of sectors total */
+ sect, /* sectors per track */
+ head, /* nr of heads */
+ track, /* nr of tracks */
+ stretch; /* !=0 means double track steps */
+#define FD_STRETCH 1
+#define FD_SWAPSIDES 2
+
+ unsigned char gap, /* gap1 size */
+
+ rate, /* data rate. |= 0x40 for perpendicular */
+#define FD_2M 0x4
+#define FD_SIZECODEMASK 0x38
+#define FD_SIZECODE(floppy) (((((floppy)->rate&FD_SIZECODEMASK)>> 3)+ 2) %8)
+#define FD_SECTSIZE(floppy) ( (floppy)->rate & FD_2M ? \
+ 512 : 128 << FD_SIZECODE(floppy) )
+#define FD_PERP 0x40
+
+ spec1, /* stepping rate, head unload time */
+ fmt_gap; /* gap2 size */
+ const char * name; /* used only for predefined formats */
+};
+struct format_descr {
+ unsigned int device,head,track;
+};
+#define FDFMTBEG _IO(2,0x47)
+#define FDFMTTRK _IOW(2,0x48, struct format_descr)
+#define FDFMTEND _IO(2,0x49)
+#define FDGETPRM _IOR(2, 0x04, struct floppy_struct)
+#define FD_FILL_BYTE 0xF6 /* format fill byte. */
+
+int fdformat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int fdformat_main(int argc UNUSED_PARAM, char **argv)
+{
+ 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 */
+ }
+
+ /* O_RDWR for formatting and verifying */
+ fd = xopen(*argv, O_RDWR);
+
+ /* original message was: "Could not determine current format type" */
+ xioctl(fd, FDGETPRM, ¶m);
+
+ 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);
+ }
+ }
+
+ 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");
+ }
+
+ 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/ap/app/busybox/src/util-linux/fdisk.c b/ap/app/busybox/src/util-linux/fdisk.c
new file mode 100644
index 0000000..39eb27b
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/fdisk.c
@@ -0,0 +1,3122 @@
+/* vi: set sw=4 ts=4: */
+/* fdisk.c -- Partition table manipulator for Linux.
+ *
+ * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
+ * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (initial bb port)
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* Looks like someone forgot to add this to config system */
+//usage:#ifndef ENABLE_FEATURE_FDISK_BLKSIZE
+//usage:# define ENABLE_FEATURE_FDISK_BLKSIZE 0
+//usage:# define IF_FEATURE_FDISK_BLKSIZE(a)
+//usage:#endif
+//usage:
+//usage:#define fdisk_trivial_usage
+//usage: "[-ul" IF_FEATURE_FDISK_BLKSIZE("s") "] "
+//usage: "[-C CYLINDERS] [-H HEADS] [-S SECTORS] [-b SSZ] DISK"
+//usage:#define fdisk_full_usage "\n\n"
+//usage: "Change partition table\n"
+//usage: "\n -u Start and End are in sectors (instead of cylinders)"
+//usage: "\n -l Show partition table for each DISK, then exit"
+//usage: IF_FEATURE_FDISK_BLKSIZE(
+//usage: "\n -s Show partition sizes in kb for each DISK, then exit"
+//usage: )
+//usage: "\n -b 2048 (for certain MO disks) use 2048-byte sectors"
+//usage: "\n -C CYLINDERS Set number of cylinders/heads/sectors"
+//usage: "\n -H HEADS"
+//usage: "\n -S SECTORS"
+
+#ifndef _LARGEFILE64_SOURCE
+/* For lseek64 */
+# define _LARGEFILE64_SOURCE
+#endif
+#include <assert.h> /* assert */
+#include <sys/mount.h>
+#if !defined(BLKSSZGET)
+# define BLKSSZGET _IO(0x12, 104)
+#endif
+#if !defined(BLKGETSIZE64)
+# define BLKGETSIZE64 _IOR(0x12,114,size_t)
+#endif
+#include "libbb.h"
+
+#if BB_LITTLE_ENDIAN
+# define inline_if_little_endian ALWAYS_INLINE
+#else
+# define inline_if_little_endian /* nothing */
+#endif
+
+
+/* Looks like someone forgot to add this to config system */
+#ifndef ENABLE_FEATURE_FDISK_BLKSIZE
+# define ENABLE_FEATURE_FDISK_BLKSIZE 0
+# define IF_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,
+};
+
+
+typedef unsigned long long ullong;
+/* Used for sector numbers. Partition formats we know
+ * do not support more than 2^32 sectors
+ */
+typedef uint32_t sector_t;
+#if UINT_MAX == 4294967295
+# define SECT_FMT ""
+#elif ULONG_MAX == 4294967295
+# define SECT_FMT "l"
+#else
+# error Cant detect sizeof(uint32_t)
+#endif
+
+struct hd_geometry {
+ unsigned char heads;
+ unsigned char sectors;
+ unsigned short cylinders;
+ unsigned long start;
+};
+
+#define HDIO_GETGEO 0x0301 /* get device geometry */
+
+static const char msg_building_new_label[] 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";
+
+static const char msg_part_already_defined[] ALIGN1 =
+"Partition %u is already defined, delete it before re-adding\n";
+
+
+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;
+
+/*
+ * 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 */
+ sector_t offset_from_dev_start; /* disk sector number */
+ char *sectorbuffer; /* disk sector contents */
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ char changed; /* boolean */
+#endif
+};
+
+#define unable_to_open "can't open '%s'"
+#define unable_to_read "can't read from %s"
+#define unable_to_seek "can't seek on %s"
+
+enum label_type {
+ LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF, LABEL_GPT
+};
+
+#define LABEL_IS_DOS (LABEL_DOS == current_label_type)
+
+#if ENABLE_FEATURE_SUN_LABEL
+#define LABEL_IS_SUN (LABEL_SUN == current_label_type)
+#define STATIC_SUN static
+#else
+#define LABEL_IS_SUN 0
+#define STATIC_SUN extern
+#endif
+
+#if ENABLE_FEATURE_SGI_LABEL
+#define LABEL_IS_SGI (LABEL_SGI == current_label_type)
+#define STATIC_SGI static
+#else
+#define LABEL_IS_SGI 0
+#define STATIC_SGI extern
+#endif
+
+#if ENABLE_FEATURE_AIX_LABEL
+#define LABEL_IS_AIX (LABEL_AIX == current_label_type)
+#define STATIC_AIX static
+#else
+#define LABEL_IS_AIX 0
+#define STATIC_AIX extern
+#endif
+
+#if ENABLE_FEATURE_OSF_LABEL
+#define LABEL_IS_OSF (LABEL_OSF == current_label_type)
+#define STATIC_OSF static
+#else
+#define LABEL_IS_OSF 0
+#define STATIC_OSF extern
+#endif
+
+#if ENABLE_FEATURE_GPT_LABEL
+#define LABEL_IS_GPT (LABEL_GPT == current_label_type)
+#define STATIC_GPT static
+#else
+#define LABEL_IS_GPT 0
+#define STATIC_GPT 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 unsigned get_partition(int warn, unsigned max);
+static void list_types(const char *const *sys);
+static sector_t read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg);
+#endif
+static const char *partition_type(unsigned char type);
+static void get_geometry(void);
+static void read_pte(struct pte *pe, sector_t offset);
+#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 sector_t get_start_sect(const struct partition *p);
+static sector_t get_nr_sects(const struct partition *p);
+
+/* DOS partition types */
+
+static const char *const i386_sys_types[] = {
+ "\x00" "Empty",
+ "\x01" "FAT12",
+ "\x04" "FAT16 <32M",
+ "\x05" "Extended", /* DOS 3.3+ extended partition */
+ "\x06" "FAT16", /* DOS 16-bit >=32M */
+ "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
+ "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
+ "\x0b" "Win95 FAT32",
+ "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
+ "\x0e" "Win95 FAT16 (LBA)",
+ "\x0f" "Win95 Ext'd (LBA)",
+ "\x11" "Hidden FAT12",
+ "\x12" "Compaq diagnostics",
+ "\x14" "Hidden FAT16 <32M",
+ "\x16" "Hidden FAT16",
+ "\x17" "Hidden HPFS/NTFS",
+ "\x1b" "Hidden Win95 FAT32",
+ "\x1c" "Hidden W95 FAT32 (LBA)",
+ "\x1e" "Hidden W95 FAT16 (LBA)",
+ "\x3c" "Part.Magic recovery",
+ "\x41" "PPC PReP Boot",
+ "\x42" "SFS",
+ "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
+ "\x80" "Old Minix", /* Minix 1.4a and earlier */
+ "\x81" "Minix / old Linux",/* Minix 1.4b and later */
+ "\x82" "Linux swap", /* also Solaris */
+ "\x83" "Linux",
+ "\x84" "OS/2 hidden C: drive",
+ "\x85" "Linux extended",
+ "\x86" "NTFS volume set",
+ "\x87" "NTFS volume set",
+ "\x8e" "Linux LVM",
+ "\x9f" "BSD/OS", /* BSDI */
+ "\xa0" "Thinkpad hibernation",
+ "\xa5" "FreeBSD", /* various BSD flavours */
+ "\xa6" "OpenBSD",
+ "\xa8" "Darwin UFS",
+ "\xa9" "NetBSD",
+ "\xab" "Darwin boot",
+ "\xb7" "BSDI fs",
+ "\xb8" "BSDI swap",
+ "\xbe" "Solaris boot",
+ "\xeb" "BeOS fs",
+ "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
+ "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
+ "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
+ "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
+ "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
+ autodetect using persistent
+ superblock */
+#if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
+ "\x02" "XENIX root",
+ "\x03" "XENIX usr",
+ "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
+ "\x09" "AIX bootable", /* AIX data or Coherent */
+ "\x10" "OPUS",
+ "\x18" "AST SmartSleep",
+ "\x24" "NEC DOS",
+ "\x39" "Plan 9",
+ "\x40" "Venix 80286",
+ "\x4d" "QNX4.x",
+ "\x4e" "QNX4.x 2nd part",
+ "\x4f" "QNX4.x 3rd part",
+ "\x50" "OnTrack DM",
+ "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
+ "\x52" "CP/M", /* CP/M or Microport SysV/AT */
+ "\x53" "OnTrack DM6 Aux3",
+ "\x54" "OnTrackDM6",
+ "\x55" "EZ-Drive",
+ "\x56" "Golden Bow",
+ "\x5c" "Priam Edisk",
+ "\x61" "SpeedStor",
+ "\x64" "Novell Netware 286",
+ "\x65" "Novell Netware 386",
+ "\x70" "DiskSecure Multi-Boot",
+ "\x75" "PC/IX",
+ "\x93" "Amoeba",
+ "\x94" "Amoeba BBT", /* (bad block table) */
+ "\xa7" "NeXTSTEP",
+ "\xbb" "Boot Wizard hidden",
+ "\xc1" "DRDOS/sec (FAT-12)",
+ "\xc4" "DRDOS/sec (FAT-16 < 32M)",
+ "\xc6" "DRDOS/sec (FAT-16)",
+ "\xc7" "Syrinx",
+ "\xda" "Non-FS data",
+ "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
+ Concurrent DOS or CTOS */
+ "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
+ "\xdf" "BootIt", /* BootIt EMBRM */
+ "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
+ extended partition */
+ "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
+ "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
+ partition < 1024 cyl. */
+ "\xf1" "SpeedStor",
+ "\xf4" "SpeedStor", /* SpeedStor large partition */
+ "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
+ "\xff" "BBT", /* Xenix Bad Block Table */
+#endif
+ NULL
+};
+
+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;
+ sector_t extended_offset; /* offset of link pointers */
+ sector_t 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? */
+/* TODO: return unsigned long long, FEATURE_FDISK_BLKSIZE _can_ handle
+ * disks > 2^32 sectors
+ */
+static sector_t bb_BLKGETSIZE_sectors(int fd)
+{
+ uint64_t v64;
+ unsigned long longsectors;
+
+ if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
+ /* Got bytes, convert to 512 byte sectors */
+ v64 >>= 9;
+ if (v64 != (sector_t)v64) {
+ ret_trunc:
+ /* Not only DOS, but all other partition tables
+ * we support can't record more than 32 bit
+ * sector counts or offsets
+ */
+ bb_error_msg("device has more than 2^32 sectors, can't use all of them");
+ v64 = (uint32_t)-1L;
+ }
+ return v64;
+ }
+ /* Needs temp of type long */
+ if (ioctl(fd, BLKGETSIZE, &longsectors)) {
+ /* Perhaps this is a disk image */
+ off_t sz = lseek(fd, 0, SEEK_END);
+ longsectors = 0;
+ if (sz > 0)
+ longsectors = (uoff_t)sz / sector_size;
+ lseek(fd, 0, SEEK_SET);
+ }
+ if (sizeof(long) > sizeof(sector_t)
+ && longsectors != (sector_t)longsectors
+ ) {
+ goto ret_trunc;
+ }
+ return longsectors;
+}
+
+
+#define IS_EXTENDED(i) \
+ ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
+
+#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
+
+#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
+
+#define pt_offset(b, n) \
+ ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
+
+#define sector(s) ((s) & 0x3f)
+
+#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
+
+#define hsc2sector(h,s,c) \
+ (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
+
+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);
+}
+
+/*
+ * Return partition name - uses static storage
+ */
+static const char *
+partname(const char *dev, int pno, int lth)
+{
+ const char *p;
+ int w, wp;
+ int bufsiz;
+ char *bufp;
+
+ bufp = partname_buffer;
+ bufsiz = sizeof(partname_buffer);
+
+ w = strlen(dev);
+ p = "";
+
+ if (isdigit(dev[w-1]))
+ p = "p";
+
+ /* devfs kludge - note: fdisk partition names are not supposed
+ to equal kernel names, so there is no reason to do this */
+ if (strcmp(dev + w - 4, "disc") == 0) {
+ w -= 4;
+ p = "part";
+ }
+
+ wp = strlen(p);
+
+ if (lth) {
+ snprintf(bufp, bufsiz, "%*.*s%s%-2u",
+ lth-wp-2, w, dev, p, pno);
+ } else {
+ snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
+ }
+ return bufp;
+}
+
+static ALWAYS_INLINE struct partition *
+get_part_table(int i)
+{
+ return ptes[i].part_table;
+}
+
+static const char *
+str_units(int n)
+{ /* n==1: use singular */
+ if (n == 1)
+ return display_in_cyl_units ? "cylinder" : "sector";
+ return display_in_cyl_units ? "cylinders" : "sectors";
+}
+
+static int
+valid_part_table_flag(const char *mbuffer)
+{
+ return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
+}
+
+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
+seek_sector(sector_t secno)
+{
+#if ENABLE_FDISK_SUPPORT_LARGE_DISKS
+ off64_t off = (off64_t)secno * sector_size;
+ if (lseek64(dev_fd, off, SEEK_SET) == (off64_t) -1)
+ fdisk_fatal(unable_to_seek);
+#else
+ uint64_t off = (uint64_t)secno * sector_size;
+ if (off > MAXINT(off_t)
+ || lseek(dev_fd, (off_t)off, SEEK_SET) == (off_t) -1
+ ) {
+ fdisk_fatal(unable_to_seek);
+ }
+#endif
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+/* Read line; return 0 or first printable char */
+static int
+read_line(const char *prompt)
+{
+ int sz;
+
+ sz = read_line_input(NULL, prompt, line_buffer, sizeof(line_buffer), /*timeout*/ -1);
+ if (sz <= 0)
+ exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */
+
+ if (line_buffer[sz-1] == '\n')
+ line_buffer[--sz] = '\0';
+
+ line_ptr = line_buffer;
+ while (*line_ptr != '\0' && (unsigned char)*line_ptr <= ' ')
+ line_ptr++;
+ return *line_ptr;
+}
+
+static void
+set_all_unchanged(void)
+{
+ int i;
+
+ for (i = 0; i < MAXIMUM_PARTS; i++)
+ ptes[i].changed = 0;
+}
+
+static ALWAYS_INLINE void
+set_changed(int i)
+{
+ ptes[i].changed = 1;
+}
+
+static ALWAYS_INLINE void
+write_part_table_flag(char *b)
+{
+ b[510] = 0x55;
+ b[511] = 0xaa;
+}
+
+static char
+read_nonempty(const char *mesg)
+{
+ while (!read_line(mesg))
+ continue;
+ return *line_ptr;
+}
+
+static char
+read_maybe_empty(const char *mesg)
+{
+ if (!read_line(mesg)) {
+ line_ptr = line_buffer;
+ line_ptr[0] = '\n';
+ line_ptr[1] = '\0';
+ }
+ return line_ptr[0];
+}
+
+static int
+read_hex(const char *const *sys)
+{
+ unsigned long v;
+ while (1) {
+ read_nonempty("Hex code (type L to list codes): ");
+ if ((line_ptr[0] | 0x20) == 'l') {
+ list_types(sys);
+ continue;
+ }
+ v = bb_strtoul(line_ptr, NULL, 16);
+ if (v <= 0xff)
+ return v;
+ }
+}
+
+static void
+write_sector(sector_t secno, const void *buf)
+{
+ seek_sector(secno);
+ xwrite(dev_fd, buf, sector_size);
+}
+#endif /* FEATURE_FDISK_WRITABLE */
+
+
+#include "fdisk_aix.c"
+
+struct sun_partition {
+ unsigned char info[128]; /* Informative text string */
+ unsigned char spare0[14];
+ struct sun_info {
+ unsigned char spare1;
+ unsigned char id;
+ unsigned char spare2;
+ unsigned char flags;
+ } infos[8];
+ unsigned char spare1[246]; /* Boot information etc. */
+ unsigned short rspeed; /* Disk rotational speed */
+ unsigned short pcylcount; /* Physical cylinder count */
+ unsigned short sparecyl; /* extra sects per cylinder */
+ unsigned char spare2[4]; /* More magic... */
+ unsigned short ilfact; /* Interleave factor */
+ unsigned short ncyl; /* Data cylinder count */
+ unsigned short nacyl; /* Alt. cylinder count */
+ unsigned short ntrks; /* Tracks per cylinder */
+ unsigned short nsect; /* Sectors per track */
+ unsigned char spare3[4]; /* Even more magic... */
+ struct sun_partinfo {
+ uint32_t start_cylinder;
+ uint32_t num_sectors;
+ } partitions[8];
+ unsigned short magic; /* Magic number */
+ unsigned short csum; /* Label xor'd checksum */
+} FIX_ALIASING;
+typedef struct sun_partition sun_partition;
+#define sunlabel ((sun_partition *)MBRbuffer)
+STATIC_OSF void bsd_select(void);
+STATIC_OSF void xbsd_print_disklabel(int);
+#include "fdisk_osf.c"
+
+STATIC_GPT void gpt_list_table(int xtra);
+#include "fdisk_gpt.c"
+
+#if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
+static uint16_t
+fdisk_swap16(uint16_t x)
+{
+ return (x << 8) | (x >> 8);
+}
+
+static uint32_t
+fdisk_swap32(uint32_t x)
+{
+ return (x << 24) |
+ ((x & 0xFF00) << 8) |
+ ((x & 0xFF0000) >> 8) |
+ (x >> 24);
+}
+#endif
+
+STATIC_SGI const char *const sgi_sys_types[];
+STATIC_SGI unsigned sgi_get_num_sectors(int i);
+STATIC_SGI int sgi_get_sysid(int i);
+STATIC_SGI void sgi_delete_partition(int i);
+STATIC_SGI void sgi_change_sysid(int i, int sys);
+STATIC_SGI void sgi_list_table(int xtra);
+#if ENABLE_FEATURE_FDISK_ADVANCED
+STATIC_SGI void sgi_set_xcyl(void);
+#endif
+STATIC_SGI int verify_sgi(int verbose);
+STATIC_SGI void sgi_add_partition(int n, int sys);
+STATIC_SGI void sgi_set_swappartition(int i);
+STATIC_SGI const char *sgi_get_bootfile(void);
+STATIC_SGI void sgi_set_bootfile(const char* aFile);
+STATIC_SGI void create_sgiinfo(void);
+STATIC_SGI void sgi_write_table(void);
+STATIC_SGI void sgi_set_bootpartition(int i);
+#include "fdisk_sgi.c"
+
+STATIC_SUN const char *const sun_sys_types[];
+STATIC_SUN void sun_delete_partition(int i);
+STATIC_SUN void sun_change_sysid(int i, int sys);
+STATIC_SUN void sun_list_table(int xtra);
+STATIC_SUN void add_sun_partition(int n, int sys);
+#if ENABLE_FEATURE_FDISK_ADVANCED
+STATIC_SUN void sun_set_alt_cyl(void);
+STATIC_SUN void sun_set_ncyl(int cyl);
+STATIC_SUN void sun_set_xcyl(void);
+STATIC_SUN void sun_set_ilfact(void);
+STATIC_SUN void sun_set_rspeed(void);
+STATIC_SUN void sun_set_pcylcount(void);
+#endif
+STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
+STATIC_SUN void verify_sun(void);
+STATIC_SUN void sun_write_table(void);
+#include "fdisk_sun.c"
+
+
+static inline_if_little_endian unsigned
+read4_little_endian(const unsigned char *cp)
+{
+ uint32_t v;
+ move_from_unaligned32(v, cp);
+ return SWAP_LE32(v);
+}
+
+static sector_t
+get_start_sect(const struct partition *p)
+{
+ return read4_little_endian(p->start4);
+}
+
+static sector_t
+get_nr_sects(const struct partition *p)
+{
+ return read4_little_endian(p->size4);
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+/* start_sect and nr_sects are stored little endian on all machines */
+/* moreover, they are not aligned correctly */
+static inline_if_little_endian void
+store4_little_endian(unsigned char *cp, unsigned val)
+{
+ uint32_t v = SWAP_LE32(val);
+ move_to_unaligned32(cp, v);
+}
+
+static void
+set_start_sect(struct partition *p, unsigned start_sect)
+{
+ store4_little_endian(p->start4, start_sect);
+}
+
+static void
+set_nr_sects(struct partition *p, unsigned nr_sects)
+{
+ store4_little_endian(p->size4, nr_sects);
+}
+#endif
+
+/* Allocate a buffer and read a partition table sector */
+static void
+read_pte(struct pte *pe, sector_t offset)
+{
+ pe->offset_from_dev_start = offset;
+ pe->sectorbuffer = xzalloc(sector_size);
+ seek_sector(offset);
+ /* 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);
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ pe->changed = 0;
+#endif
+ pe->part_table = pe->ext_pointer = NULL;
+}
+
+static sector_t
+get_partition_start_from_dev_start(const struct pte *pe)
+{
+ return pe->offset_from_dev_start + get_start_sect(pe->part_table);
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+/*
+ * Avoid warning about DOS partitions when no DOS partition was changed.
+ * Here a heuristic "is probably dos partition".
+ * We might also do the opposite and warn in all cases except
+ * for "is probably nondos partition".
+ */
+#ifdef UNUSED
+static int
+is_dos_partition(int t)
+{
+ return (t == 1 || t == 4 || t == 6 ||
+ t == 0x0b || t == 0x0c || t == 0x0e ||
+ t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
+ t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
+ t == 0xc1 || t == 0xc4 || t == 0xc6);
+}
+#endif
+
+static void
+menu(void)
+{
+ puts("Command Action");
+ if (LABEL_IS_SUN) {
+ puts("a\ttoggle a read only flag"); /* sun */
+ puts("b\tedit bsd disklabel");
+ puts("c\ttoggle the mountable flag"); /* sun */
+ puts("d\tdelete a partition");
+ puts("l\tlist known partition types");
+ puts("n\tadd a new partition");
+ puts("o\tcreate a new empty DOS partition table");
+ puts("p\tprint the partition table");
+ puts("q\tquit without saving changes");
+ puts("s\tcreate a new empty Sun disklabel"); /* sun */
+ puts("t\tchange a partition's system id");
+ puts("u\tchange display/entry units");
+ puts("v\tverify the partition table");
+ puts("w\twrite table to disk and exit");
+#if ENABLE_FEATURE_FDISK_ADVANCED
+ puts("x\textra functionality (experts only)");
+#endif
+ } else if (LABEL_IS_SGI) {
+ puts("a\tselect bootable partition"); /* sgi flavour */
+ puts("b\tedit bootfile entry"); /* sgi */
+ puts("c\tselect sgi swap partition"); /* sgi flavour */
+ puts("d\tdelete a partition");
+ puts("l\tlist known partition types");
+ puts("n\tadd a new partition");
+ puts("o\tcreate a new empty DOS partition table");
+ puts("p\tprint the partition table");
+ puts("q\tquit without saving changes");
+ puts("s\tcreate a new empty Sun disklabel"); /* sun */
+ puts("t\tchange a partition's system id");
+ puts("u\tchange display/entry units");
+ puts("v\tverify the partition table");
+ puts("w\twrite table to disk and exit");
+ } else if (LABEL_IS_AIX) {
+ puts("o\tcreate a new empty DOS partition table");
+ puts("q\tquit without saving changes");
+ puts("s\tcreate a new empty Sun disklabel"); /* sun */
+ } else if (LABEL_IS_GPT) {
+ 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 */
+ } else {
+ puts("a\ttoggle a bootable flag");
+ puts("b\tedit bsd disklabel");
+ puts("c\ttoggle the dos compatibility flag");
+ puts("d\tdelete a partition");
+ puts("l\tlist known partition types");
+ puts("n\tadd a new partition");
+ puts("o\tcreate a new empty DOS partition table");
+ puts("p\tprint the partition table");
+ puts("q\tquit without saving changes");
+ puts("s\tcreate a new empty Sun disklabel"); /* sun */
+ puts("t\tchange a partition's system id");
+ puts("u\tchange display/entry units");
+ puts("v\tverify the partition table");
+ puts("w\twrite table to disk and exit");
+#if ENABLE_FEATURE_FDISK_ADVANCED
+ puts("x\textra functionality (experts only)");
+#endif
+ }
+}
+#endif /* FEATURE_FDISK_WRITABLE */
+
+
+#if ENABLE_FEATURE_FDISK_ADVANCED
+static void
+xmenu(void)
+{
+ puts("Command Action");
+ if (LABEL_IS_SUN) {
+ puts("a\tchange number of alternate cylinders"); /*sun*/
+ puts("c\tchange number of cylinders");
+ puts("d\tprint the raw data in the partition table");
+ puts("e\tchange number of extra sectors per cylinder");/*sun*/
+ puts("h\tchange number of heads");
+ puts("i\tchange interleave factor"); /*sun*/
+ puts("o\tchange rotation speed (rpm)"); /*sun*/
+ puts("p\tprint the partition table");
+ puts("q\tquit without saving changes");
+ puts("r\treturn to main menu");
+ puts("s\tchange number of sectors/track");
+ puts("v\tverify the partition table");
+ puts("w\twrite table to disk and exit");
+ puts("y\tchange number of physical cylinders"); /*sun*/
+ } else if (LABEL_IS_SGI) {
+ puts("b\tmove beginning of data in a partition"); /* !sun */
+ puts("c\tchange number of cylinders");
+ puts("d\tprint the raw data in the partition table");
+ puts("e\tlist extended partitions"); /* !sun */
+ puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
+ puts("h\tchange number of heads");
+ puts("p\tprint the partition table");
+ puts("q\tquit without saving changes");
+ puts("r\treturn to main menu");
+ puts("s\tchange number of sectors/track");
+ puts("v\tverify the partition table");
+ puts("w\twrite table to disk and exit");
+ } else if (LABEL_IS_AIX) {
+ puts("b\tmove beginning of data in a partition"); /* !sun */
+ puts("c\tchange number of cylinders");
+ puts("d\tprint the raw data in the partition table");
+ puts("e\tlist extended partitions"); /* !sun */
+ puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
+ puts("h\tchange number of heads");
+ puts("p\tprint the partition table");
+ puts("q\tquit without saving changes");
+ puts("r\treturn to main menu");
+ puts("s\tchange number of sectors/track");
+ puts("v\tverify the partition table");
+ puts("w\twrite table to disk and exit");
+ } else {
+ puts("b\tmove beginning of data in a partition"); /* !sun */
+ puts("c\tchange number of cylinders");
+ puts("d\tprint the raw data in the partition table");
+ puts("e\tlist extended partitions"); /* !sun */
+ puts("f\tfix partition order"); /* !sun, !aix, !sgi */
+#if ENABLE_FEATURE_SGI_LABEL
+ puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
+#endif
+ puts("h\tchange number of heads");
+ puts("p\tprint the partition table");
+ puts("q\tquit without saving changes");
+ puts("r\treturn to main menu");
+ puts("s\tchange number of sectors/track");
+ puts("v\tverify the partition table");
+ puts("w\twrite table to disk and exit");
+ }
+}
+#endif /* ADVANCED mode */
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static const char *const *
+get_sys_types(void)
+{
+ return (
+ LABEL_IS_SUN ? sun_sys_types :
+ LABEL_IS_SGI ? sgi_sys_types :
+ i386_sys_types);
+}
+#else
+#define get_sys_types() i386_sys_types
+#endif
+
+static const char *
+partition_type(unsigned char type)
+{
+ int i;
+ const char *const *types = get_sys_types();
+
+ for (i = 0; types[i]; i++)
+ if ((unsigned char)types[i][0] == type)
+ return types[i] + 1;
+
+ return "Unknown";
+}
+
+static int
+is_cleared_partition(const struct partition *p)
+{
+ /* We consider partition "cleared" only if it has only zeros */
+ const char *cp = (const char *)p;
+ int cnt = sizeof(*p);
+ char bits = 0;
+ while (--cnt >= 0)
+ bits |= *cp++;
+ return (bits == 0);
+}
+
+static void
+clear_partition(struct partition *p)
+{
+ if (p)
+ memset(p, 0, sizeof(*p));
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static int
+get_sysid(int i)
+{
+ return LABEL_IS_SUN ? sunlabel->infos[i].id :
+ (LABEL_IS_SGI ? sgi_get_sysid(i) :
+ ptes[i].part_table->sys_ind);
+}
+
+static void
+list_types(const char *const *sys)
+{
+ enum { COLS = 3 };
+
+ unsigned last[COLS];
+ unsigned done, next, size;
+ int i;
+
+ for (size = 0; sys[size]; size++)
+ continue;
+
+ done = 0;
+ for (i = COLS-1; i >= 0; i--) {
+ done += (size + i - done) / (i + 1);
+ last[COLS-1 - i] = done;
+ }
+
+ i = done = next = 0;
+ do {
+ printf("%c%2x %-22.22s", i ? ' ' : '\n',
+ (unsigned char)sys[next][0],
+ sys[next] + 1);
+ next = last[i++] + done;
+ if (i >= COLS || next >= last[i]) {
+ i = 0;
+ next = ++done;
+ }
+ } while (done < last[0]);
+ bb_putchar('\n');
+}
+
+#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)
+
+static void set_hsc_start_end(struct partition *p, sector_t start, sector_t stop)
+{
+ 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 / (g_sectors * g_heads) > 1023))
+ stop = g_heads * g_sectors * 1024 - 1;
+ set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
+}
+
+static void
+set_partition(int i, int doext, sector_t start, sector_t stop, int sysid)
+{
+ struct partition *p;
+ sector_t offset;
+
+ if (doext) {
+ p = ptes[i].ext_pointer;
+ offset = extended_offset;
+ } else {
+ p = ptes[i].part_table;
+ offset = ptes[i].offset_from_dev_start;
+ }
+ p->boot_ind = 0;
+ p->sys_ind = sysid;
+ set_start_sect(p, start - offset);
+ set_nr_sects(p, stop - start + 1);
+ set_hsc_start_end(p, start, stop);
+ ptes[i].changed = 1;
+}
+#endif
+
+static int
+warn_geometry(void)
+{
+ if (g_heads && g_sectors && g_cylinders)
+ return 0;
+
+ 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)
+{
+ int cyl_units = g_heads * g_sectors;
+
+ if (display_in_cyl_units && cyl_units)
+ units_per_sector = cyl_units;
+ else
+ units_per_sector = 1; /* in sectors */
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static void
+warn_cylinders(void)
+{
+ if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
+ printf("\n"
+"The number of cylinders for this disk is set to %u.\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",
+ g_cylinders);
+}
+#endif
+
+static void
+read_extended(int ext)
+{
+ int i;
+ struct pte *pex;
+ struct partition *p, *q;
+
+ ext_index = ext;
+ pex = &ptes[ext];
+ pex->ext_pointer = pex->part_table;
+
+ p = pex->part_table;
+ if (!get_start_sect(p)) {
+ printf("Bad offset in primary extended partition\n");
+ return;
+ }
+
+ while (IS_EXTENDED(p->sys_ind)) {
+ struct pte *pe = &ptes[g_partitions];
+
+ 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[g_partitions - 1];
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ printf("Warning: deleting partitions after %u\n",
+ g_partitions);
+ pre->changed = 1;
+#endif
+ clear_partition(pre->ext_pointer);
+ return;
+ }
+
+ read_pte(pe, extended_offset + get_start_sect(p));
+
+ if (!extended_offset)
+ extended_offset = get_start_sect(p);
+
+ q = p = pt_offset(pe->sectorbuffer, 0);
+ for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
+ if (IS_EXTENDED(p->sys_ind)) {
+ if (pe->ext_pointer)
+ printf("Warning: extra link "
+ "pointer in partition table"
+ " %u\n", g_partitions + 1);
+ else
+ pe->ext_pointer = p;
+ } else if (p->sys_ind) {
+ if (pe->part_table)
+ printf("Warning: ignoring extra "
+ "data in partition table"
+ " %u\n", g_partitions + 1);
+ else
+ pe->part_table = p;
+ }
+ }
+
+ /* very strange code here... */
+ if (!pe->part_table) {
+ if (q != pe->ext_pointer)
+ pe->part_table = q;
+ else
+ pe->part_table = q + 1;
+ }
+ if (!pe->ext_pointer) {
+ if (q != pe->part_table)
+ pe->ext_pointer = q;
+ else
+ pe->ext_pointer = q + 1;
+ }
+
+ p = pe->ext_pointer;
+ g_partitions++;
+ }
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ /* remove empty links */
+ remove:
+ for (i = 4; i < g_partitions; i++) {
+ struct pte *pe = &ptes[i];
+
+ if (!get_nr_sects(pe->part_table)
+ && (g_partitions > 5 || ptes[4].part_table->sys_ind)
+ ) {
+ printf("Omitting empty partition (%u)\n", i+1);
+ delete_partition(i);
+ goto remove; /* numbering changed */
+ }
+ }
+#endif
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static void
+create_doslabel(void)
+{
+ printf(msg_building_new_label, "DOS disklabel");
+
+ current_label_type = LABEL_DOS;
+#if ENABLE_FEATURE_OSF_LABEL
+ possibly_osf_label = 0;
+#endif
+ g_partitions = 4;
+
+ memset(&MBRbuffer[510 - 4*16], 0, 4*16);
+ write_part_table_flag(MBRbuffer);
+ extended_offset = 0;
+ set_all_unchanged();
+ set_changed(0);
+ get_boot(CREATE_EMPTY_DOS);
+}
+#endif
+
+static void
+get_sectorsize(void)
+{
+ if (!user_set_sector_size) {
+ int arg;
+ if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
+ sector_size = arg;
+ if (sector_size != DEFAULT_SECTOR_SIZE)
+ printf("Note: sector size is %u "
+ "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
+ sector_size);
+ }
+}
+
+static void
+get_kernel_geometry(void)
+{
+ struct hd_geometry geometry;
+
+ if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
+ kern_heads = geometry.heads;
+ kern_sectors = geometry.sectors;
+ /* never use geometry.cylinders - it is truncated */
+ }
+}
+
+static void
+get_partition_table_geometry(void)
+{
+ const unsigned char *bufp = (const unsigned char *)MBRbuffer;
+ struct partition *p;
+ int i, h, s, hh, ss;
+ int first = 1;
+ int bad = 0;
+
+ if (!(valid_part_table_flag((char*)bufp)))
+ return;
+
+ hh = ss = 0;
+ for (i = 0; i < 4; i++) {
+ p = pt_offset(bufp, i);
+ if (p->sys_ind != 0) {
+ h = p->end_head + 1;
+ s = (p->end_sector & 077);
+ if (first) {
+ hh = h;
+ ss = s;
+ first = 0;
+ } else if (hh != h || ss != s)
+ bad = 1;
+ }
+ }
+
+ if (!first && !bad) {
+ pt_heads = hh;
+ pt_sectors = ss;
+ }
+}
+
+static void
+get_geometry(void)
+{
+ int sec_fac;
+
+ get_sectorsize();
+ sec_fac = sector_size / 512;
+#if ENABLE_FEATURE_SUN_LABEL
+ guess_device_type();
+#endif
+ g_heads = g_cylinders = g_sectors = 0;
+ kern_heads = kern_sectors = 0;
+ pt_heads = pt_sectors = 0;
+
+ get_kernel_geometry();
+ get_partition_table_geometry();
+
+ g_heads = user_heads ? user_heads :
+ pt_heads ? pt_heads :
+ kern_heads ? kern_heads : 255;
+ g_sectors = user_sectors ? user_sectors :
+ pt_sectors ? pt_sectors :
+ kern_sectors ? kern_sectors : 63;
+ total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
+
+ sector_offset = 1;
+ if (dos_compatible_flag)
+ sector_offset = g_sectors;
+
+ g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
+ if (!g_cylinders)
+ g_cylinders = user_cylinders;
+}
+
+/*
+ * Opens disk_device and optionally reads MBR.
+ * If what == OPEN_MAIN:
+ * Open device, read MBR. Abort program on short read. Create empty
+ * disklabel if the on-disk structure is invalid (WRITABLE mode).
+ * If what == TRY_ONLY:
+ * Open device, read MBR. Return an error if anything is out of place.
+ * Do not create an empty disklabel. This is used for the "list"
+ * operations: "fdisk -l /dev/sda" and "fdisk -l" (all devices).
+ * If what == CREATE_EMPTY_*:
+ * This means that get_boot() was called recursively from create_*label().
+ * Do not re-open the device; just set up the ptes array and print
+ * geometry warnings.
+ *
+ * Returns:
+ * -1: no 0xaa55 flag present (possibly entire disk BSD)
+ * 0: found or created label
+ * 1: I/O error
+ */
+#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_from_dev_start = 0;
+ pe->sectorbuffer = MBRbuffer;
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ pe->changed = (what == CREATE_EMPTY_DOS);
+#endif
+ }
+
+#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 IF_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
+ goto created_table;
+
+ fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
+
+ 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);
+ }
+ 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
+ fd = open(disk_device, O_RDONLY);
+ if (fd < 0)
+ return 1;
+ if (512 != full_read(fd, MBRbuffer, 512)) {
+ close(fd);
+ return 1;
+ }
+ xmove_fd(fd, dev_fd);
+#endif
+
+ get_geometry();
+ update_units();
+
+#if ENABLE_FEATURE_SUN_LABEL
+ if (check_sun_label())
+ return 0;
+#endif
+#if ENABLE_FEATURE_SGI_LABEL
+ if (check_sgi_label())
+ return 0;
+#endif
+#if ENABLE_FEATURE_AIX_LABEL
+ if (check_aix_label())
+ return 0;
+#endif
+#if ENABLE_FEATURE_GPT_LABEL
+ if (check_gpt_label())
+ return 0;
+#endif
+#if ENABLE_FEATURE_OSF_LABEL
+ if (check_osf_label()) {
+ possibly_osf_label = 1;
+ if (!valid_part_table_flag(MBRbuffer)) {
+ current_label_type = LABEL_OSF;
+ return 0;
+ }
+ printf("This disk has both DOS and BSD magic.\n"
+ "Give the 'b' command to go to BSD mode.\n");
+ }
+#endif
+
+#if !ENABLE_FEATURE_FDISK_WRITABLE
+ if (!valid_part_table_flag(MBRbuffer))
+ return -1;
+#else
+ if (!valid_part_table_flag(MBRbuffer)) {
+ if (what == OPEN_MAIN) {
+ printf("Device contains neither a valid DOS "
+ "partition table, nor Sun, SGI, OSF or GPT "
+ "disklabel\n");
+#ifdef __sparc__
+ IF_FEATURE_SUN_LABEL(create_sunlabel();)
+#else
+ create_doslabel();
+#endif
+ return 0;
+ }
+ /* TRY_ONLY: */
+ return -1;
+ }
+ created_table:
+#endif /* FEATURE_FDISK_WRITABLE */
+
+
+ IF_FEATURE_FDISK_WRITABLE(warn_cylinders();)
+ warn_geometry();
+
+ for (i = 0; i < 4; i++) {
+ if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
+ if (g_partitions != 4)
+ printf("Ignoring extra extended "
+ "partition %u\n", i + 1);
+ else
+ read_extended(i);
+ }
+ }
+
+ for (i = 3; i < g_partitions; i++) {
+ struct pte *pe = &ptes[i];
+ if (!valid_part_table_flag(pe->sectorbuffer)) {
+ printf("Warning: invalid flag 0x%02x,0x%02x of partition "
+ "table %u will be corrected by w(rite)\n",
+ pe->sectorbuffer[510],
+ pe->sectorbuffer[511],
+ i + 1);
+ IF_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
+ }
+ }
+
+ return 0;
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+/*
+ * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
+ * If the user hits Enter, DFLT is returned.
+ * Answers like +10 are interpreted as offsets from BASE.
+ *
+ * There is no default if DFLT is not between LOW and HIGH.
+ */
+static sector_t
+read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg)
+{
+ sector_t value;
+ int default_ok = 1;
+ const char *fmt = "%s (%u-%u, default %u): ";
+
+ if (dflt < low || dflt > high) {
+ fmt = "%s (%u-%u): ";
+ default_ok = 0;
+ }
+
+ while (1) {
+ int use_default = default_ok;
+
+ /* ask question and read answer */
+ do {
+ printf(fmt, mesg, low, high, dflt);
+ read_maybe_empty("");
+ } while (*line_ptr != '\n' && !isdigit(*line_ptr)
+ && *line_ptr != '-' && *line_ptr != '+');
+
+ if (*line_ptr == '+' || *line_ptr == '-') {
+ int minus = (*line_ptr == '-');
+ int absolute = 0;
+
+ value = atoi(line_ptr + 1);
+
+ /* (1) if 2nd char is digit, use_default = 0.
+ * (2) move line_ptr to first non-digit. */
+ while (isdigit(*++line_ptr))
+ use_default = 0;
+
+ switch (*line_ptr) {
+ case 'c':
+ case 'C':
+ if (!display_in_cyl_units)
+ value *= 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 (absolute) {
+ ullong bytes;
+ unsigned long unit;
+
+ bytes = (ullong) value * absolute;
+ unit = sector_size * units_per_sector;
+ bytes += unit/2; /* round */
+ bytes /= unit;
+ value = bytes;
+ }
+ if (minus)
+ value = -value;
+ value += base;
+ } else {
+ value = atoi(line_ptr);
+ while (isdigit(*line_ptr)) {
+ line_ptr++;
+ use_default = 0;
+ }
+ }
+ if (use_default) {
+ value = dflt;
+ printf("Using default value %u\n", value);
+ }
+ if (value >= low && value <= high)
+ break;
+ printf("Value is out of range\n");
+ }
+ return value;
+}
+
+static unsigned
+get_partition(int warn, unsigned max)
+{
+ struct pte *pe;
+ unsigned i;
+
+ i = read_int(1, 0, max, 0, "Partition number") - 1;
+ pe = &ptes[i];
+
+ if (warn) {
+ if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
+ || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
+ || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
+ ) {
+ printf("Warning: partition %u has empty type\n", i+1);
+ }
+ }
+ return i;
+}
+
+static int
+get_existing_partition(int warn, unsigned max)
+{
+ int pno = -1;
+ unsigned i;
+
+ for (i = 0; i < max; i++) {
+ struct pte *pe = &ptes[i];
+ struct partition *p = pe->part_table;
+
+ if (p && !is_cleared_partition(p)) {
+ if (pno >= 0)
+ goto not_unique;
+ pno = i;
+ }
+ }
+ if (pno >= 0) {
+ printf("Selected partition %u\n", pno+1);
+ return pno;
+ }
+ printf("No partition is defined yet!\n");
+ return -1;
+
+ not_unique:
+ return get_partition(warn, max);
+}
+
+static int
+get_nonexisting_partition(int warn, unsigned max)
+{
+ int pno = -1;
+ unsigned i;
+
+ for (i = 0; i < max; i++) {
+ struct pte *pe = &ptes[i];
+ struct partition *p = pe->part_table;
+
+ if (p && is_cleared_partition(p)) {
+ if (pno >= 0)
+ goto not_unique;
+ pno = i;
+ }
+ }
+ if (pno >= 0) {
+ printf("Selected partition %u\n", pno+1);
+ return pno;
+ }
+ printf("All primary partitions have been defined already!\n");
+ return -1;
+
+ not_unique:
+ return get_partition(warn, max);
+}
+
+
+static void
+change_units(void)
+{
+ display_in_cyl_units = !display_in_cyl_units;
+ update_units();
+ printf("Changing display/entry units to %s\n",
+ str_units(PLURAL));
+}
+
+static void
+toggle_active(int i)
+{
+ struct pte *pe = &ptes[i];
+ struct partition *p = pe->part_table;
+
+ if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
+ printf("WARNING: Partition %u 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 = 1 - dos_compatible_flag;
+ if (dos_compatible_flag) {
+ sector_offset = g_sectors;
+ printf("DOS Compatibility flag is set\n");
+ } else {
+ sector_offset = 1;
+ printf("DOS Compatibility flag is not set\n");
+ }
+}
+
+static void
+delete_partition(int i)
+{
+ struct pte *pe = &ptes[i];
+ struct partition *p = pe->part_table;
+ struct partition *q = pe->ext_pointer;
+
+/* Note that for the fifth partition (i == 4) we don't actually
+ * decrement partitions.
+ */
+
+ if (warn_geometry())
+ return; /* C/H/S not set */
+ pe->changed = 1;
+
+ if (LABEL_IS_SUN) {
+ sun_delete_partition(i);
+ return;
+ }
+ if (LABEL_IS_SGI) {
+ sgi_delete_partition(i);
+ return;
+ }
+
+ if (i < 4) {
+ if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
+ g_partitions = 4;
+ ptes[ext_index].ext_pointer = NULL;
+ extended_offset = 0;
+ }
+ clear_partition(p);
+ return;
+ }
+
+ if (!q->sys_ind && i > 4) {
+ /* the last one in the chain - just delete */
+ --g_partitions;
+ --i;
+ clear_partition(ptes[i].ext_pointer);
+ ptes[i].changed = 1;
+ } else {
+ /* not the last one - further ones will be moved down */
+ if (i > 4) {
+ /* delete this link in the chain */
+ p = ptes[i-1].ext_pointer;
+ *p = *q;
+ set_start_sect(p, get_start_sect(q));
+ set_nr_sects(p, get_nr_sects(q));
+ ptes[i-1].changed = 1;
+ } else if (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_from_dev_start(pe) -
+ extended_offset);
+ pe->offset_from_dev_start = extended_offset;
+ pe->changed = 1;
+ }
+
+ if (g_partitions > 5) {
+ g_partitions--;
+ while (i < g_partitions) {
+ ptes[i] = ptes[i+1];
+ i++;
+ }
+ } else {
+ /* the only logical: clear only */
+ clear_partition(ptes[i].part_table);
+ }
+ }
+}
+
+static void
+change_sysid(void)
+{
+ int i, sys, origsys;
+ struct partition *p;
+
+ /* If sgi_label then don't use get_existing_partition,
+ let the user select a partition, since get_existing_partition()
+ only works for Linux like partition tables. */
+ if (!LABEL_IS_SGI) {
+ i = get_existing_partition(0, g_partitions);
+ } else {
+ i = get_partition(0, g_partitions);
+ }
+ if (i == -1)
+ return;
+ p = ptes[i].part_table;
+ origsys = sys = get_sysid(i);
+
+ /* if changing types T to 0 is allowed, then
+ the reverse change must be allowed, too */
+ if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
+ printf("Partition %u does not exist yet!\n", i + 1);
+ return;
+ }
+ while (1) {
+ sys = read_hex(get_sys_types());
+
+ if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
+ printf("Type 0 means free space to many systems\n"
+ "(but not to Linux). Having partitions of\n"
+ "type 0 is probably unwise.\n");
+ /* break; */
+ }
+
+ if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
+ if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
+ printf("You cannot change a partition into"
+ " an extended one or vice versa\n");
+ break;
+ }
+ }
+
+ if (sys < 256) {
+#if ENABLE_FEATURE_SUN_LABEL
+ if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
+ printf("Consider leaving partition 3 "
+ "as Whole disk (5),\n"
+ "as SunOS/Solaris expects it and "
+ "even Linux likes it\n\n");
+#endif
+#if ENABLE_FEATURE_SGI_LABEL
+ if (LABEL_IS_SGI &&
+ (
+ (i == 10 && sys != SGI_ENTIRE_DISK) ||
+ (i == 8 && sys != 0)
+ )
+ ) {
+ printf("Consider leaving partition 9 "
+ "as volume header (0),\nand "
+ "partition 11 as entire volume (6)"
+ "as IRIX expects it\n\n");
+ }
+#endif
+ if (sys == origsys)
+ break;
+ if (LABEL_IS_SUN) {
+ sun_change_sysid(i, sys);
+ } else if (LABEL_IS_SGI) {
+ sgi_change_sysid(i, sys);
+ } else
+ p->sys_ind = sys;
+
+ printf("Changed system type of partition %u "
+ "to %x (%s)\n", i + 1, sys,
+ partition_type(sys));
+ ptes[i].changed = 1;
+ //if (is_dos_partition(origsys) || is_dos_partition(sys))
+ // dos_changed = 1;
+ break;
+ }
+ }
+}
+#endif /* FEATURE_FDISK_WRITABLE */
+
+
+/* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
+ * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
+ * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
+ * Lubkin Oct. 1991). */
+
+static void
+linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
+{
+ int spc = g_heads * g_sectors;
+
+ *c = ls / spc;
+ ls = ls % spc;
+ *h = ls / g_sectors;
+ *s = ls % g_sectors + 1; /* sectors count from 1 */
+}
+
+static void
+check_consistency(const struct partition *p, int partition)
+{
+ unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
+ unsigned pec, peh, pes; /* physical ending c, h, s */
+ unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
+ unsigned lec, leh, les; /* logical ending c, h, s */
+
+ if (!g_heads || !g_sectors || (partition >= 4))
+ return; /* do not check extended partitions */
+
+/* physical beginning c, h, s */
+ pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
+ pbh = p->head;
+ pbs = p->sector & 0x3f;
+
+/* physical ending c, h, s */
+ pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
+ peh = p->end_head;
+ pes = p->end_sector & 0x3f;
+
+/* compute logical beginning (c, h, s) */
+ linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
+
+/* compute logical ending (c, h, s) */
+ linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
+
+/* Same physical / logical beginning? */
+ if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
+ printf("Partition %u has different physical/logical "
+ "beginnings (non-Linux?):\n", partition + 1);
+ printf(" phys=(%u, %u, %u) ", pbc, pbh, pbs);
+ printf("logical=(%u, %u, %u)\n", lbc, lbh, lbs);
+ }
+
+/* Same physical / logical ending? */
+ if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
+ printf("Partition %u has different physical/logical "
+ "endings:\n", partition + 1);
+ printf(" phys=(%u, %u, %u) ", pec, peh, pes);
+ printf("logical=(%u, %u, %u)\n", lec, leh, les);
+ }
+
+/* Ending on cylinder boundary? */
+ if (peh != (g_heads - 1) || pes != g_sectors) {
+ printf("Partition %u does not end on cylinder boundary\n",
+ partition + 1);
+ }
+}
+
+static void
+list_disk_geometry(void)
+{
+ ullong bytes = ((ullong)total_number_of_sectors << 9);
+ long megabytes = bytes / 1000000;
+
+ if (megabytes < 10000)
+ printf("\nDisk %s: %lu MB, %llu bytes\n",
+ disk_device, megabytes, bytes);
+ else
+ printf("\nDisk %s: %lu.%lu GB, %llu bytes\n",
+ disk_device, megabytes/1000, (megabytes/100)%10, bytes);
+ printf("%u heads, %u sectors/track, %u cylinders",
+ g_heads, g_sectors, g_cylinders);
+ if (units_per_sector == 1)
+ printf(", total %"SECT_FMT"u sectors",
+ total_number_of_sectors / (sector_size/512));
+ printf("\nUnits = %s of %u * %u = %u bytes\n\n",
+ str_units(PLURAL),
+ units_per_sector, sector_size, units_per_sector * sector_size);
+}
+
+/*
+ * Check whether partition entries are ordered by their starting positions.
+ * Return 0 if OK. Return i if partition i should have been earlier.
+ * Two separate checks: primary and logical partitions.
+ */
+static int
+wrong_p_order(int *prev)
+{
+ const struct pte *pe;
+ const struct partition *p;
+ sector_t last_p_start_pos = 0, p_start_pos;
+ unsigned i, last_i = 0;
+
+ for (i = 0; i < g_partitions; i++) {
+ if (i == 4) {
+ last_i = 4;
+ last_p_start_pos = 0;
+ }
+ pe = &ptes[i];
+ p = pe->part_table;
+ if (p->sys_ind) {
+ p_start_pos = get_partition_start_from_dev_start(pe);
+
+ if (last_p_start_pos > p_start_pos) {
+ if (prev)
+ *prev = last_i;
+ return i;
+ }
+
+ last_p_start_pos = p_start_pos;
+ last_i = i;
+ }
+ }
+ return 0;
+}
+
+#if ENABLE_FEATURE_FDISK_ADVANCED
+/*
+ * Fix the chain of logicals.
+ * extended_offset is unchanged, the set of sectors used is unchanged
+ * The chain is sorted so that sectors increase, and so that
+ * starting sectors increase.
+ *
+ * After this it may still be that cfdisk doesnt like the table.
+ * (This is because cfdisk considers expanded parts, from link to
+ * end of partition, and these may still overlap.)
+ * Now
+ * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
+ * may help.
+ */
+static void
+fix_chain_of_logicals(void)
+{
+ int j, oj, ojj, sj, sjj;
+ struct partition *pj,*pjj,tmp;
+
+ /* Stage 1: sort sectors but leave sector of part 4 */
+ /* (Its sector is the global extended_offset.) */
+ stage1:
+ for (j = 5; j < g_partitions - 1; j++) {
+ oj = ptes[j].offset_from_dev_start;
+ ojj = ptes[j+1].offset_from_dev_start;
+ if (oj > ojj) {
+ ptes[j].offset_from_dev_start = ojj;
+ ptes[j+1].offset_from_dev_start = oj;
+ pj = ptes[j].part_table;
+ set_start_sect(pj, get_start_sect(pj)+oj-ojj);
+ pjj = ptes[j+1].part_table;
+ set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
+ set_start_sect(ptes[j-1].ext_pointer,
+ ojj-extended_offset);
+ set_start_sect(ptes[j].ext_pointer,
+ oj-extended_offset);
+ goto stage1;
+ }
+ }
+
+ /* Stage 2: sort starting sectors */
+ stage2:
+ for (j = 4; j < g_partitions - 1; j++) {
+ pj = ptes[j].part_table;
+ pjj = ptes[j+1].part_table;
+ sj = get_start_sect(pj);
+ sjj = get_start_sect(pjj);
+ oj = ptes[j].offset_from_dev_start;
+ ojj = ptes[j+1].offset_from_dev_start;
+ if (oj+sj > ojj+sjj) {
+ tmp = *pj;
+ *pj = *pjj;
+ *pjj = tmp;
+ set_start_sect(pj, ojj+sjj-oj);
+ set_start_sect(pjj, oj+sj-ojj);
+ goto stage2;
+ }
+ }
+
+ /* Probably something was changed */
+ for (j = 4; j < g_partitions; j++)
+ ptes[j].changed = 1;
+}
+
+
+static void
+fix_partition_table_order(void)
+{
+ struct pte *pei, *pek;
+ int i,k;
+
+ if (!wrong_p_order(NULL)) {
+ printf("Ordering is already correct\n\n");
+ return;
+ }
+
+ while ((i = wrong_p_order(&k)) != 0 && i < 4) {
+ /* partition i should have come earlier, move it */
+ /* We have to move data in the MBR */
+ struct partition *pi, *pk, *pe, pbuf;
+ pei = &ptes[i];
+ pek = &ptes[k];
+
+ pe = pei->ext_pointer;
+ pei->ext_pointer = pek->ext_pointer;
+ pek->ext_pointer = pe;
+
+ pi = pei->part_table;
+ pk = pek->part_table;
+
+ memmove(&pbuf, pi, sizeof(struct partition));
+ memmove(pi, pk, sizeof(struct partition));
+ memmove(pk, &pbuf, sizeof(struct partition));
+
+ pei->changed = pek->changed = 1;
+ }
+
+ if (i)
+ fix_chain_of_logicals();
+
+ printf("Done.\n");
+}
+#endif
+
+static void
+list_table(int xtra)
+{
+ const struct partition *p;
+ int i, w;
+
+ if (LABEL_IS_SUN) {
+ sun_list_table(xtra);
+ return;
+ }
+ if (LABEL_IS_SGI) {
+ sgi_list_table(xtra);
+ return;
+ }
+ if (LABEL_IS_GPT) {
+ gpt_list_table(xtra);
+ return;
+ }
+
+ list_disk_geometry();
+
+ if (LABEL_IS_OSF) {
+ xbsd_print_disklabel(xtra);
+ return;
+ }
+
+ /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
+ but if the device name ends in a digit, say /dev/foo1,
+ then the partition is called /dev/foo1p3. */
+ w = strlen(disk_device);
+ if (w && isdigit(disk_device[w-1]))
+ w++;
+ if (w < 5)
+ w = 5;
+
+ // 1 12345678901 12345678901 12345678901 12
+ printf("%*s Boot Start End Blocks Id System\n",
+ w+1, "Device");
+
+ for (i = 0; i < g_partitions; i++) {
+ const struct pte *pe = &ptes[i];
+ sector_t psects;
+ sector_t pblocks;
+ unsigned podd;
+
+ p = pe->part_table;
+ if (!p || is_cleared_partition(p))
+ continue;
+
+ psects = get_nr_sects(p);
+ pblocks = psects;
+ podd = 0;
+
+ if (sector_size < 1024) {
+ pblocks /= (1024 / sector_size);
+ podd = psects % (1024 / sector_size);
+ }
+ if (sector_size > 1024)
+ pblocks *= (sector_size / 1024);
+
+ printf("%s %c %11"SECT_FMT"u %11"SECT_FMT"u %11"SECT_FMT"u%c %2x %s\n",
+ partname(disk_device, i+1, w+2),
+ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
+ ? '*' : '?',
+ cround(get_partition_start_from_dev_start(pe)), /* start */
+ cround(get_partition_start_from_dev_start(pe) + psects /* end */
+ - (psects ? 1 : 0)),
+ pblocks, podd ? '+' : ' ', /* odd flag on end */
+ p->sys_ind, /* type id */
+ partition_type(p->sys_ind)); /* type name */
+
+ check_consistency(p, i);
+ }
+
+ /* Is partition table in disk order? It need not be, but... */
+ /* partition table entries are not checked for correct order
+ * if this is a sgi, sun or aix labeled disk... */
+ if (LABEL_IS_DOS && wrong_p_order(NULL)) {
+ /* FIXME */
+ printf("\nPartition table entries are not in disk order\n");
+ }
+}
+
+#if ENABLE_FEATURE_FDISK_ADVANCED
+static void
+x_list_table(int extend)
+{
+ const struct pte *pe;
+ const struct partition *p;
+ int i;
+
+ printf("\nDisk %s: %u heads, %u sectors, %u 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) {
+ printf("%2u %02x%4u%4u%5u%4u%4u%5u%11"SECT_FMT"u%11"SECT_FMT"u %02x\n",
+ i + 1, p->boot_ind, p->head,
+ sector(p->sector),
+ cylinder(p->sector, p->cyl), p->end_head,
+ sector(p->end_sector),
+ cylinder(p->end_sector, p->end_cyl),
+ get_start_sect(p), get_nr_sects(p),
+ p->sys_ind);
+ if (p->sys_ind)
+ check_consistency(p, i);
+ }
+ }
+}
+#endif
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static void
+fill_bounds(sector_t *first, sector_t *last)
+{
+ unsigned i;
+ const struct pte *pe = &ptes[0];
+ const struct partition *p;
+
+ for (i = 0; i < g_partitions; pe++,i++) {
+ p = pe->part_table;
+ if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
+ first[i] = 0xffffffff;
+ last[i] = 0;
+ } else {
+ first[i] = get_partition_start_from_dev_start(pe);
+ last[i] = first[i] + get_nr_sects(p) - 1;
+ }
+ }
+}
+
+static void
+check(int n, unsigned h, unsigned s, unsigned c, sector_t start)
+{
+ sector_t total, real_s, real_c;
+
+ real_s = sector(s) - 1;
+ real_c = cylinder(s, c);
+ total = (real_c * g_sectors + real_s) * g_heads + h;
+ if (!total)
+ printf("Partition %u contains sector 0\n", n);
+ if (h >= g_heads)
+ printf("Partition %u: head %u greater than maximum %u\n",
+ n, h + 1, g_heads);
+ if (real_s >= g_sectors)
+ printf("Partition %u: sector %u greater than "
+ "maximum %u\n", n, s, g_sectors);
+ if (real_c >= g_cylinders)
+ printf("Partition %u: cylinder %"SECT_FMT"u greater than "
+ "maximum %u\n", n, real_c + 1, g_cylinders);
+ if (g_cylinders <= 1024 && start != total)
+ printf("Partition %u: previous sectors %"SECT_FMT"u disagrees with "
+ "total %"SECT_FMT"u\n", n, start, total);
+}
+
+static void
+verify(void)
+{
+ int i, j;
+ sector_t total = 1;
+ sector_t first[g_partitions], last[g_partitions];
+ struct partition *p;
+
+ if (warn_geometry())
+ return;
+
+ if (LABEL_IS_SUN) {
+ verify_sun();
+ return;
+ }
+ if (LABEL_IS_SGI) {
+ verify_sgi(1);
+ return;
+ }
+
+ fill_bounds(first, last);
+ for (i = 0; i < g_partitions; i++) {
+ struct pte *pe = &ptes[i];
+
+ p = pe->part_table;
+ if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
+ check_consistency(p, i);
+ if (get_partition_start_from_dev_start(pe) < first[i])
+ printf("Warning: bad start-of-data in "
+ "partition %u\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 %u overlaps "
+ "partition %u\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];
+ sector_t e_last = get_start_sect(pex->part_table) +
+ get_nr_sects(pex->part_table) - 1;
+
+ for (i = 4; i < g_partitions; i++) {
+ total++;
+ p = ptes[i].part_table;
+ if (!p->sys_ind) {
+ if (i != 4 || i + 1 < g_partitions)
+ printf("Warning: partition %u "
+ "is empty\n", i + 1);
+ } else if (first[i] < extended_offset || last[i] > e_last) {
+ printf("Logical partition %u not entirely in "
+ "partition %u\n", i + 1, ext_index + 1);
+ }
+ }
+ }
+
+ if (total > g_heads * g_sectors * g_cylinders)
+ printf("Total allocated sectors %u greater than the maximum "
+ "%u\n", total, g_heads * g_sectors * g_cylinders);
+ else {
+ total = g_heads * g_sectors * g_cylinders - total;
+ if (total != 0)
+ printf("%"SECT_FMT"u unallocated sectors\n", total);
+ }
+}
+
+static void
+add_partition(int n, int sys)
+{
+ char mesg[256]; /* 48 does not suffice in Japanese */
+ int i, num_read = 0;
+ struct partition *p = ptes[n].part_table;
+ struct partition *q = ptes[ext_index].part_table;
+ sector_t limit, temp;
+ sector_t start, stop = 0;
+ sector_t first[g_partitions], last[g_partitions];
+
+ if (p && p->sys_ind) {
+ printf(msg_part_already_defined, n + 1);
+ return;
+ }
+ fill_bounds(first, last);
+ if (n < 4) {
+ start = sector_offset;
+ if (display_in_cyl_units || !total_number_of_sectors)
+ limit = (sector_t) g_heads * g_sectors * g_cylinders - 1;
+ else
+ limit = total_number_of_sectors - 1;
+ if (extended_offset) {
+ first[ext_index] = extended_offset;
+ last[ext_index] = get_start_sect(q) +
+ get_nr_sects(q) - 1;
+ }
+ } else {
+ start = extended_offset + sector_offset;
+ limit = get_start_sect(q) + get_nr_sects(q) - 1;
+ }
+ if (display_in_cyl_units)
+ 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));
+ do {
+ temp = start;
+ for (i = 0; i < g_partitions; i++) {
+ int lastplusoff;
+
+ if (start == ptes[i].offset_from_dev_start)
+ start += sector_offset;
+ lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
+ if (start >= first[i] && start <= lastplusoff)
+ start = lastplusoff + 1;
+ }
+ if (start > limit)
+ break;
+ if (start >= temp+units_per_sector && num_read) {
+ printf("Sector %"SECT_FMT"u is already allocated\n", temp);
+ temp = start;
+ num_read = 0;
+ }
+ if (!num_read && start == temp) {
+ sector_t saved_start;
+
+ saved_start = start;
+ start = read_int(cround(saved_start), cround(saved_start), cround(limit), 0, mesg);
+ if (display_in_cyl_units) {
+ start = (start - 1) * units_per_sector;
+ if (start < saved_start)
+ start = saved_start;
+ }
+ num_read = 1;
+ }
+ } while (start != temp || !num_read);
+ if (n > 4) { /* NOT for fifth partition */
+ struct pte *pe = &ptes[n];
+
+ pe->offset_from_dev_start = start - sector_offset;
+ if (pe->offset_from_dev_start == extended_offset) { /* must be corrected */
+ pe->offset_from_dev_start++;
+ if (sector_offset == 1)
+ start++;
+ }
+ }
+
+ for (i = 0; i < g_partitions; i++) {
+ struct pte *pe = &ptes[i];
+
+ if (start < pe->offset_from_dev_start && limit >= pe->offset_from_dev_start)
+ limit = pe->offset_from_dev_start - 1;
+ if (start < first[i] && limit >= first[i])
+ limit = first[i] - 1;
+ }
+ if (start > limit) {
+ printf("No free sectors available\n");
+ if (n > 4)
+ g_partitions--;
+ return;
+ }
+ if (cround(start) == cround(limit)) {
+ stop = limit;
+ } else {
+ snprintf(mesg, sizeof(mesg),
+ "Last %s or +size or +sizeM or +sizeK",
+ str_units(SINGULAR));
+ stop = read_int(cround(start), cround(limit), cround(limit), cround(start), mesg);
+ if (display_in_cyl_units) {
+ stop = stop * units_per_sector - 1;
+ if (stop >limit)
+ stop = limit;
+ }
+ }
+
+ set_partition(n, 0, start, stop, sys);
+ if (n > 4)
+ set_partition(n - 1, 1, ptes[n].offset_from_dev_start, stop, EXTENDED);
+
+ if (IS_EXTENDED(sys)) {
+ struct pte *pe4 = &ptes[4];
+ struct pte *pen = &ptes[n];
+
+ ext_index = n;
+ pen->ext_pointer = p;
+ pe4->offset_from_dev_start = extended_offset = start;
+ pe4->sectorbuffer = xzalloc(sector_size);
+ pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
+ pe4->ext_pointer = pe4->part_table + 1;
+ pe4->changed = 1;
+ g_partitions = 5;
+ }
+}
+
+static void
+add_logical(void)
+{
+ if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
+ struct pte *pe = &ptes[g_partitions];
+
+ pe->sectorbuffer = xzalloc(sector_size);
+ pe->part_table = pt_offset(pe->sectorbuffer, 0);
+ pe->ext_pointer = pe->part_table + 1;
+ pe->offset_from_dev_start = 0;
+ pe->changed = 1;
+ g_partitions++;
+ }
+ add_partition(g_partitions - 1, LINUX_NATIVE);
+}
+
+static void
+new_partition(void)
+{
+ int i, free_primary = 0;
+
+ if (warn_geometry())
+ return;
+
+ if (LABEL_IS_SUN) {
+ add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
+ return;
+ }
+ if (LABEL_IS_SGI) {
+ sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
+ return;
+ }
+ if (LABEL_IS_AIX) {
+ printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
+"If you want to add DOS-type partitions, create a new empty DOS partition\n"
+"table first (use 'o'). This will destroy the present disk contents.\n");
+ return;
+ }
+
+ for (i = 0; i < 4; i++)
+ free_primary += !ptes[i].part_table->sys_ind;
+
+ if (!free_primary && 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");
+ } else {
+ char c, line[80];
+ snprintf(line, sizeof(line),
+ "Command action\n"
+ " %s\n"
+ " p primary partition (1-4)\n",
+ (extended_offset ?
+ "l logical (5 or over)" : "e extended"));
+ while (1) {
+ c = read_nonempty(line);
+ if ((c | 0x20) == 'p') {
+ i = get_nonexisting_partition(0, 4);
+ if (i >= 0)
+ add_partition(i, LINUX_NATIVE);
+ return;
+ }
+ if (c == 'l' && extended_offset) {
+ add_logical();
+ return;
+ }
+ if (c == 'e' && !extended_offset) {
+ i = get_nonexisting_partition(0, 4);
+ if (i >= 0)
+ add_partition(i, EXTENDED);
+ return;
+ }
+ printf("Invalid partition number "
+ "for type '%c'\n", c);
+ }
+ }
+}
+
+static void
+reread_partition_table(int leave)
+{
+ int i;
+
+ printf("Calling ioctl() to re-read partition table\n");
+ sync();
+ /* Users with slow external USB disks on a 320MHz ARM system (year 2011)
+ * report that sleep is needed, otherwise BLKRRPART may fail with -EIO:
+ */
+ sleep(1);
+ 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"
+ "partitions, please see the fdisk manual page for additional\n"
+ "information\n");
+#endif
+
+ if (leave) {
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close_dev_fd();
+ exit(i != 0);
+ }
+}
+
+static void
+write_table(void)
+{
+ int i;
+
+ if (LABEL_IS_DOS) {
+ for (i = 0; i < 3; i++)
+ if (ptes[i].changed)
+ ptes[3].changed = 1;
+ for (i = 3; i < g_partitions; i++) {
+ struct pte *pe = &ptes[i];
+ if (pe->changed) {
+ write_part_table_flag(pe->sectorbuffer);
+ write_sector(pe->offset_from_dev_start, pe->sectorbuffer);
+ }
+ }
+ }
+ else if (LABEL_IS_SGI) {
+ /* no test on change? the printf below might be mistaken */
+ sgi_write_table();
+ }
+ else if (LABEL_IS_SUN) {
+ for (i = 0; i < 8; i++) {
+ if (ptes[i].changed) {
+ sun_write_table();
+ break;
+ }
+ }
+ }
+
+ printf("The partition table has been altered.\n");
+ reread_partition_table(1);
+}
+#endif /* FEATURE_FDISK_WRITABLE */
+
+#if ENABLE_FEATURE_FDISK_ADVANCED
+#define MAX_PER_LINE 16
+static void
+print_buffer(char *pbuffer)
+{
+ int i,l;
+
+ for (i = 0, l = 0; i < sector_size; i++, l++) {
+ if (l == 0)
+ printf("0x%03X:", i);
+ printf(" %02X", (unsigned char) pbuffer[i]);
+ if (l == MAX_PER_LINE - 1) {
+ bb_putchar('\n');
+ l = -1;
+ }
+ }
+ if (l > 0)
+ bb_putchar('\n');
+ bb_putchar('\n');
+}
+
+static void
+print_raw(void)
+{
+ int i;
+
+ printf("Device: %s\n", disk_device);
+ if (LABEL_IS_SGI || LABEL_IS_SUN)
+ print_buffer(MBRbuffer);
+ else {
+ for (i = 3; i < g_partitions; i++)
+ print_buffer(ptes[i].sectorbuffer);
+ }
+}
+
+static void
+move_begin(unsigned i)
+{
+ struct pte *pe = &ptes[i];
+ struct partition *p = pe->part_table;
+ sector_t new, first, nr_sects;
+
+ if (warn_geometry())
+ return;
+ nr_sects = get_nr_sects(p);
+ if (!p->sys_ind || !nr_sects || IS_EXTENDED(p->sys_ind)) {
+ printf("Partition %u has no data area\n", i + 1);
+ return;
+ }
+ first = get_partition_start_from_dev_start(pe); /* == pe->offset_from_dev_start + get_start_sect(p) */
+ new = read_int(0 /*was:first*/, first, first + nr_sects - 1, first, "New beginning of data");
+ if (new != first) {
+ sector_t new_relative = new - pe->offset_from_dev_start;
+ nr_sects += (get_start_sect(p) - new_relative);
+ set_start_sect(p, new_relative);
+ set_nr_sects(p, nr_sects);
+ read_nonempty("Recalculate C/H/S values? (Y/N): ");
+ if ((line_ptr[0] | 0x20) == 'y')
+ set_hsc_start_end(p, new, new + nr_sects - 1);
+ pe->changed = 1;
+ }
+}
+
+static void
+xselect(void)
+{
+ char c;
+
+ while (1) {
+ bb_putchar('\n');
+ c = 0x20 | read_nonempty("Expert command (m for help): ");
+ switch (c) {
+ case 'a':
+ if (LABEL_IS_SUN)
+ sun_set_alt_cyl();
+ break;
+ case 'b':
+ if (LABEL_IS_DOS)
+ move_begin(get_partition(0, g_partitions));
+ break;
+ case 'c':
+ 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':
+ if (LABEL_IS_SGI)
+ sgi_set_xcyl();
+ else if (LABEL_IS_SUN)
+ sun_set_xcyl();
+ else if (LABEL_IS_DOS)
+ x_list_table(1);
+ break;
+ case 'f':
+ if (LABEL_IS_DOS)
+ fix_partition_table_order();
+ break;
+ case 'g':
+#if ENABLE_FEATURE_SGI_LABEL
+ create_sgilabel();
+#endif
+ break;
+ case 'h':
+ user_heads = g_heads = read_int(1, g_heads, 256, 0, "Number of heads");
+ update_units();
+ break;
+ case 'i':
+ if (LABEL_IS_SUN)
+ sun_set_ilfact();
+ break;
+ case 'o':
+ if (LABEL_IS_SUN)
+ sun_set_rspeed();
+ break;
+ case 'p':
+ if (LABEL_IS_SUN)
+ list_table(1);
+ else
+ x_list_table(0);
+ break;
+ case 'q':
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close_dev_fd();
+ bb_putchar('\n');
+ exit(EXIT_SUCCESS);
+ case 'r':
+ return;
+ case 's':
+ user_sectors = g_sectors = read_int(1, g_sectors, 63, 0, "Number of sectors");
+ if (dos_compatible_flag) {
+ sector_offset = g_sectors;
+ printf("Warning: setting sector offset for DOS "
+ "compatiblity\n");
+ }
+ update_units();
+ break;
+ case 'v':
+ verify();
+ break;
+ case 'w':
+ write_table(); /* does not return */
+ break;
+ case 'y':
+ if (LABEL_IS_SUN)
+ sun_set_pcylcount();
+ break;
+ default:
+ xmenu();
+ }
+ }
+}
+#endif /* ADVANCED mode */
+
+static int
+is_ide_cdrom_or_tape(const char *device)
+{
+ FILE *procf;
+ char buf[100];
+ struct stat statbuf;
+ int is_ide = 0;
+
+ /* No device was given explicitly, and we are trying some
+ likely things. But opening /dev/hdc may produce errors like
+ "hdc: tray open or drive not ready"
+ if it happens to be a CD-ROM drive. It even happens that
+ the process hangs on the attempt to read a music CD.
+ So try to be careful. This only works since 2.1.73. */
+
+ if (strncmp("/dev/hd", device, 7))
+ return 0;
+
+ snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
+ procf = fopen_for_read(buf);
+ if (procf != NULL && fgets(buf, sizeof(buf), procf))
+ is_ide = (!strncmp(buf, "cdrom", 5) ||
+ !strncmp(buf, "tape", 4));
+ else
+ /* Now when this proc file does not exist, skip the
+ device when it is read-only. */
+ if (stat(device, &statbuf) == 0)
+ is_ide = ((statbuf.st_mode & 0222) == 0);
+
+ if (procf)
+ fclose(procf);
+ return is_ide;
+}
+
+
+static void
+open_list_and_close(const char *device, int user_specified)
+{
+ int gb;
+
+ disk_device = device;
+ if (setjmp(listingbuf))
+ return;
+ if (!user_specified)
+ if (is_ide_cdrom_or_tape(device))
+ return;
+
+ /* 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 (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();
+}
+
+/* Is it a whole disk? The digit check is still useful
+ for Xen devices for example. */
+static int is_whole_disk(const char *disk)
+{
+ unsigned len;
+ int fd = open(disk, O_RDONLY);
+
+ if (fd != -1) {
+ struct hd_geometry geometry;
+ int err = ioctl(fd, HDIO_GETGEO, &geometry);
+ close(fd);
+ if (!err)
+ return (geometry.start == 0);
+ }
+
+ /* Treat "nameN" as a partition name, not whole disk */
+ /* note: mmcblk0 should work from the geometry check above */
+ len = strlen(disk);
+ if (len != 0 && isdigit(disk[len - 1]))
+ return 0;
+
+ return 1;
+}
+
+/* for fdisk -l: try all things in /proc/partitions
+ that look like a partition name (do not end in a digit) */
+static void
+list_devs_in_proc_partititons(void)
+{
+ FILE *procpt;
+ char line[100], ptname[100], devname[120];
+ int ma, mi, sz;
+
+ procpt = fopen_or_warn("/proc/partitions", "r");
+
+ while (fgets(line, sizeof(line), procpt)) {
+ if (sscanf(line, " %u %u %u %[^\n ]",
+ &ma, &mi, &sz, ptname) != 4)
+ continue;
+
+ sprintf(devname, "/dev/%s", ptname);
+ if (is_whole_disk(devname))
+ open_list_and_close(devname, 0);
+ }
+#if ENABLE_FEATURE_CLEAN_UP
+ fclose(procpt);
+#endif
+}
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+static void
+unknown_command(int c)
+{
+ printf("%c: unknown command\n", c);
+}
+#endif
+
+int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int fdisk_main(int argc UNUSED_PARAM, char **argv)
+{
+ unsigned opt;
+ /*
+ * fdisk -v
+ * fdisk -l [-b sectorsize] [-u] device ...
+ * fdisk -s [partition] ...
+ * fdisk [-b sectorsize] [-u] device
+ *
+ * Options -C, -H, -S set the geometry.
+ */
+ 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" IF_FEATURE_FDISK_BLKSIZE("s"),
+ §or_size, &user_cylinders, &user_heads, &user_sectors);
+ argv += optind;
+ if (opt & OPT_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 > 0x10000
+ || (sector_size & (sector_size-1)) /* not power of 2 */
+ ) {
+ bb_show_usage();
+ }
+ 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
+ if (*argv) {
+ listing = 1;
+ do {
+ open_list_and_close(*argv, 1);
+ } while (*++argv);
+ } else {
+ /* we don't have device names, */
+ /* use /proc/partitions instead */
+ list_devs_in_proc_partititons();
+ }
+ return 0;
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ }
+#endif
+
+#if ENABLE_FEATURE_FDISK_BLKSIZE
+ if (opt & OPT_s) {
+ int j;
+
+ nowarn = 1;
+ if (!argv[0])
+ bb_show_usage();
+ for (j = 0; argv[j]; j++) {
+ unsigned long long size;
+ fd = xopen(argv[j], O_RDONLY);
+ size = bb_BLKGETSIZE_sectors(fd) / 2;
+ close(fd);
+ if (argv[1])
+ printf("%llu\n", size);
+ else
+ printf("%s: %llu\n", argv[j], size);
+ }
+ return 0;
+ }
+#endif
+
+#if ENABLE_FEATURE_FDISK_WRITABLE
+ if (!argv[0] || argv[1])
+ bb_show_usage();
+
+ disk_device = argv[0];
+ get_boot(OPEN_MAIN);
+
+ if (LABEL_IS_OSF) {
+ /* OSF label, and no DOS label */
+ printf("Detected an OSF/1 disklabel on %s, entering "
+ "disklabel mode\n", disk_device);
+ bsd_select();
+ /*Why do we do this? It seems to be counter-intuitive*/
+ current_label_type = LABEL_DOS;
+ /* If we return we may want to make an empty DOS label? */
+ }
+
+ while (1) {
+ int c;
+ bb_putchar('\n');
+ c = 0x20 | read_nonempty("Command (m for help): ");
+ switch (c) {
+ case 'a':
+ if (LABEL_IS_DOS)
+ toggle_active(get_partition(1, g_partitions));
+ else if (LABEL_IS_SUN)
+ toggle_sunflags(get_partition(1, g_partitions),
+ 0x01);
+ else if (LABEL_IS_SGI)
+ sgi_set_bootpartition(
+ get_partition(1, g_partitions));
+ else
+ unknown_command(c);
+ break;
+ case 'b':
+ if (LABEL_IS_SGI) {
+ printf("\nThe current boot file is: %s\n",
+ sgi_get_bootfile());
+ if (read_maybe_empty("Please enter the name of the "
+ "new boot file: ") == '\n')
+ printf("Boot file unchanged\n");
+ else
+ sgi_set_bootfile(line_ptr);
+ }
+#if ENABLE_FEATURE_OSF_LABEL
+ else
+ bsd_select();
+#endif
+ break;
+ case 'c':
+ if (LABEL_IS_DOS)
+ toggle_dos_compatibility_flag();
+ else if (LABEL_IS_SUN)
+ toggle_sunflags(get_partition(1, g_partitions),
+ 0x10);
+ else if (LABEL_IS_SGI)
+ sgi_set_swappartition(
+ get_partition(1, g_partitions));
+ else
+ unknown_command(c);
+ break;
+ case 'd':
+ {
+ int j;
+ /* If sgi_label then don't use get_existing_partition,
+ let the user select a partition, since
+ get_existing_partition() only works for Linux-like
+ partition tables */
+ if (!LABEL_IS_SGI) {
+ j = get_existing_partition(1, g_partitions);
+ } else {
+ j = get_partition(1, g_partitions);
+ }
+ if (j >= 0)
+ delete_partition(j);
+ }
+ break;
+ case 'i':
+ if (LABEL_IS_SGI)
+ create_sgiinfo();
+ else
+ unknown_command(c);
+ case 'l':
+ list_types(get_sys_types());
+ break;
+ case 'm':
+ menu();
+ break;
+ case 'n':
+ new_partition();
+ break;
+ case 'o':
+ create_doslabel();
+ break;
+ case 'p':
+ list_table(0);
+ break;
+ case 'q':
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close_dev_fd();
+ bb_putchar('\n');
+ return 0;
+ case 's':
+#if ENABLE_FEATURE_SUN_LABEL
+ create_sunlabel();
+#endif
+ break;
+ case 't':
+ change_sysid();
+ break;
+ case 'u':
+ change_units();
+ break;
+ case 'v':
+ verify();
+ break;
+ case 'w':
+ write_table(); /* does not return */
+ break;
+#if ENABLE_FEATURE_FDISK_ADVANCED
+ case 'x':
+ if (LABEL_IS_SGI) {
+ printf("\n\tSorry, no experts menu for SGI "
+ "partition tables available\n\n");
+ } else
+ xselect();
+ break;
+#endif
+ default:
+ unknown_command(c);
+ menu();
+ }
+ }
+ return 0;
+#endif /* FEATURE_FDISK_WRITABLE */
+}
diff --git a/ap/app/busybox/src/util-linux/fdisk_aix.c b/ap/app/busybox/src/util-linux/fdisk_aix.c
new file mode 100644
index 0000000..ee5df50
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/fdisk_aix.c
@@ -0,0 +1,74 @@
+#if ENABLE_FEATURE_AIX_LABEL
+/*
+ * Copyright (C) Andreas Neuper, Sep 1998.
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+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/ap/app/busybox/src/util-linux/fdisk_gpt.c b/ap/app/busybox/src/util-linux/fdisk_gpt.c
new file mode 100644
index 0000000..d43d9c7
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/fdisk_gpt.c
@@ -0,0 +1,195 @@
+#if ENABLE_FEATURE_GPT_LABEL
+/*
+ * Copyright (C) 2010 Kevin Cernekee <cernekee@gmail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#define GPT_MAGIC 0x5452415020494645ULL
+enum {
+ LEGACY_GPT_TYPE = 0xee,
+ GPT_MAX_PARTS = 256,
+ GPT_MAX_PART_ENTRY_LEN = 4096,
+ GUID_LEN = 16,
+};
+
+typedef struct {
+ uint64_t magic;
+ uint32_t revision;
+ uint32_t hdr_size;
+ uint32_t hdr_crc32;
+ uint32_t reserved;
+ uint64_t current_lba;
+ uint64_t backup_lba;
+ uint64_t first_usable_lba;
+ uint64_t last_usable_lba;
+ uint8_t disk_guid[GUID_LEN];
+ uint64_t first_part_lba;
+ uint32_t n_parts;
+ uint32_t part_entry_len;
+ uint32_t part_array_crc32;
+} gpt_header;
+
+typedef struct {
+ uint8_t type_guid[GUID_LEN];
+ uint8_t part_guid[GUID_LEN];
+ uint64_t lba_start;
+ uint64_t lba_end;
+ uint64_t flags;
+ uint16_t name[36];
+} gpt_partition;
+
+static gpt_header *gpt_hdr;
+
+static char *part_array;
+static unsigned int n_parts;
+static unsigned int part_array_len;
+static unsigned int part_entry_len;
+
+static inline gpt_partition *
+gpt_part(int i)
+{
+ if (i >= n_parts) {
+ return NULL;
+ }
+ return (gpt_partition *)&part_array[i * part_entry_len];
+}
+
+static uint32_t
+gpt_crc32(void *buf, int len)
+{
+ return ~crc32_block_endian0(0xffffffff, buf, len, global_crc32_table);
+}
+
+static void
+gpt_print_guid(uint8_t *buf)
+{
+ printf(
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ buf[3], buf[2], buf[1], buf[0],
+ buf[5], buf[4],
+ buf[7], buf[6],
+ buf[8], buf[9],
+ buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
+}
+
+/* TODO: real unicode support */
+static void
+gpt_print_wide(uint16_t *s, int max_len)
+{
+ int i = 0;
+
+ while (i < max_len) {
+ if (*s == 0)
+ return;
+ fputc(*s, stdout);
+ s++;
+ }
+}
+
+static void
+gpt_list_table(int xtra UNUSED_PARAM)
+{
+ int i;
+ char numstr6[6];
+
+ numstr6[5] = '\0';
+
+ smart_ulltoa5(total_number_of_sectors, numstr6, " KMGTPEZY");
+ printf("Disk %s: %llu sectors, %s\n", disk_device,
+ (unsigned long long)total_number_of_sectors,
+ numstr6);
+ printf("Logical sector size: %u\n", sector_size);
+ printf("Disk identifier (GUID): ");
+ gpt_print_guid(gpt_hdr->disk_guid);
+ printf("\nPartition table holds up to %u entries\n",
+ (int)SWAP_LE32(gpt_hdr->n_parts));
+ printf("First usable sector is %llu, last usable sector is %llu\n\n",
+ (unsigned long long)SWAP_LE64(gpt_hdr->first_usable_lba),
+ (unsigned long long)SWAP_LE64(gpt_hdr->last_usable_lba));
+
+ printf("Number Start (sector) End (sector) Size Code Name\n");
+ for (i = 0; i < n_parts; i++) {
+ gpt_partition *p = gpt_part(i);
+ if (p->lba_start) {
+ smart_ulltoa5(1 + SWAP_LE64(p->lba_end) - SWAP_LE64(p->lba_start),
+ numstr6, " KMGTPEZY");
+ printf("%4u %15llu %15llu %11s %04x ",
+ i + 1,
+ (unsigned long long)SWAP_LE64(p->lba_start),
+ (unsigned long long)SWAP_LE64(p->lba_end),
+ numstr6,
+ 0x0700 /* FIXME */);
+ gpt_print_wide(p->name, 18);
+ printf("\n");
+ }
+ }
+}
+
+static int
+check_gpt_label(void)
+{
+ struct partition *first = pt_offset(MBRbuffer, 0);
+ struct pte pe;
+ uint32_t crc;
+
+ /* LBA 0 contains the legacy MBR */
+
+ if (!valid_part_table_flag(MBRbuffer)
+ || first->sys_ind != LEGACY_GPT_TYPE
+ ) {
+ current_label_type = 0;
+ return 0;
+ }
+
+ /* LBA 1 contains the GPT header */
+
+ read_pte(&pe, 1);
+ gpt_hdr = (void *)pe.sectorbuffer;
+
+ if (gpt_hdr->magic != SWAP_LE64(GPT_MAGIC)) {
+ current_label_type = 0;
+ return 0;
+ }
+
+ if (!global_crc32_table) {
+ global_crc32_table = crc32_filltable(NULL, 0);
+ }
+
+ crc = SWAP_LE32(gpt_hdr->hdr_crc32);
+ gpt_hdr->hdr_crc32 = 0;
+ if (gpt_crc32(gpt_hdr, SWAP_LE32(gpt_hdr->hdr_size)) != crc) {
+ /* FIXME: read the backup table */
+ puts("\nwarning: GPT header CRC is invalid\n");
+ }
+
+ n_parts = SWAP_LE32(gpt_hdr->n_parts);
+ part_entry_len = SWAP_LE32(gpt_hdr->part_entry_len);
+ if (n_parts > GPT_MAX_PARTS
+ || part_entry_len > GPT_MAX_PART_ENTRY_LEN
+ || SWAP_LE32(gpt_hdr->hdr_size) > sector_size
+ ) {
+ puts("\nwarning: unable to parse GPT disklabel\n");
+ current_label_type = 0;
+ return 0;
+ }
+
+ part_array_len = n_parts * part_entry_len;
+ part_array = xmalloc(part_array_len);
+ seek_sector(SWAP_LE64(gpt_hdr->first_part_lba));
+ if (full_read(dev_fd, part_array, part_array_len) != part_array_len) {
+ fdisk_fatal(unable_to_read);
+ }
+
+ if (gpt_crc32(part_array, part_array_len) != gpt_hdr->part_array_crc32) {
+ /* FIXME: read the backup table */
+ puts("\nwarning: GPT array CRC is invalid\n");
+ }
+
+ puts("Found valid GPT with protective MBR; using GPT\n");
+
+ current_label_type = LABEL_GPT;
+ return 1;
+}
+
+#endif /* GPT_LABEL */
diff --git a/ap/app/busybox/src/util-linux/fdisk_osf.c b/ap/app/busybox/src/util-linux/fdisk_osf.c
new file mode 100644
index 0000000..ff16389
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/fdisk_osf.c
@@ -0,0 +1,1047 @@
+/*
+ * 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(__alpha__) \
+ || defined(__powerpc__) \
+ || defined(__ia64__) \
+ || defined(__hppa__)
+# define BSD_LABELSECTOR 0
+# define BSD_LABELOFFSET 64
+#else
+# define BSD_LABELSECTOR 1
+# define BSD_LABELOFFSET 0
+#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 %u\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: %u\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: %lu\n", (long) lp->d_secsize);
+ printf("sectors/track: %lu\n", (long) lp->d_nsectors);
+ printf("tracks/cylinder: %lu\n", (long) lp->d_ntracks);
+ printf("sectors/cylinder: %lu\n", (long) lp->d_secpercyl);
+ printf("cylinders: %lu\n", (long) lp->d_ncylinders);
+ printf("rpm: %u\n", lp->d_rpm);
+ printf("interleave: %u\n", lp->d_interleave);
+ printf("trackskew: %u\n", lp->d_trackskew);
+ printf("cylinderskew: %u\n", lp->d_cylskew);
+ printf("headswitch: %lu\t\t# milliseconds\n",
+ (long) lp->d_headswitch);
+ printf("track-to-track seek: %lu\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("%lu ", (long) lp->d_drivedata[j]);
+ }
+ printf("\n%u 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: %8lu%c %8lu%c %8lu%c ",
+ 'a' + i,
+ (unsigned long) pp->p_offset / lp->d_secpercyl + 1,
+ (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
+ (unsigned 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: %8lu %8lu %8lu ",
+ '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(" %5lu %5lu %5.5s ",
+ (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
+ break;
+ case BSD_FS_BSDFFS:
+ printf(" %5lu %5lu %5u ",
+ (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|0x20) == '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|0x20) == 'n')
+ return 0;
+ }
+}
+
+static int
+edit_int(int def, const char *mesg)
+{
+ mesg = xasprintf("%s (%u): ", 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 (%u, maximum is %u)\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
+ (void)p; /* silence warning */
+ 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/ap/app/busybox/src/util-linux/fdisk_sgi.c b/ap/app/busybox/src/util-linux/fdisk_sgi.c
new file mode 100644
index 0000000..785fc66
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/fdisk_sgi.c
@@ -0,0 +1,886 @@
+/*
+ * Copyright (C) Andreas Neuper, Sep 1998.
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#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): %u heads, %u sectors\n"
+ "%u cylinders, %u physical cylinders\n"
+ "%u extra sects/cyl, interleave %u:1\n"
+ "%s\n"
+ "Units = %s of %u * 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): "
+ "%u heads, %u sectors, %u cylinders\n"
+ "Units = %s of %u * 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(
+ "%2u: %s %4s %9lu %9lu %9lu %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("%2u: %-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 %u\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 %u diskblock large,\n"
+ "but the disk is %u 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=%u\tpartition=%u\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 %u 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 %u 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 %u and %u overlap by %u 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 %u sectors - sectors %u-%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 (SGI_DEBUG > 1) {
+ if (verbose)
+ printf("%2u:%12u\t%12u\t%12u\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 %u sectors - sectors %u-%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 != 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 %u.\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 %u\n", i);
+ if (SGI_DEBUG)
+ printf("ID=%02x\tSTART=%u\tLENGTH=%u\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/ap/app/busybox/src/util-linux/fdisk_sun.c b/ap/app/busybox/src/util-linux/fdisk_sun.c
new file mode 100644
index 0000000..e7fcc06
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/fdisk_sun.c
@@ -0,0 +1,729 @@
+/*
+ * 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 source tree.
+ */
+
+#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 smallint sun_other_endian;
+static smallint scsi_disk;
+static smallint 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, unsigned start, unsigned 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%u Channel: %02u Id: %02u Lun: %02u\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 %u alt %u hd %u sec %u",
+ 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(unsigned *starts, unsigned *lens, unsigned *start, unsigned *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 unsigned *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)
+{
+ unsigned 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 %u 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 %u overlaps with others in "
+ "sectors %u-%u\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 %u-%u\n", 0, starts[array[0]]);
+ for (i = 0; i < 7 && array[i+1] != -1; i++) {
+ printf("Unused gap - sectors %u-%u\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 %u-%u\n", start, stop);
+}
+
+static void
+add_sun_partition(int n, int sys)
+{
+ unsigned start, stop, stop2;
+ unsigned 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 %u 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 %u %s covers some other partition.\n"
+"Your entry has been changed to %u %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): %u heads, %u sectors, %u rpm\n"
+ "%u cylinders, %u alternate cylinders, %u physical cylinders\n"
+ "%u extra sects/cyl, interleave %u:1\n"
+ "%s\n"
+ "Units = %s of %u * 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): %u heads, %u sectors, %u cylinders\n"
+ "Units = %s of %u * 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 %9lu %9lu %9lu%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/ap/app/busybox/src/util-linux/findfs.c b/ap/app/busybox/src/util-linux/findfs.c
new file mode 100644
index 0000000..49e8979
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/findfs.c
@@ -0,0 +1,47 @@
+/* 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 source tree.
+ */
+
+//usage:#define findfs_trivial_usage
+//usage: "LABEL=label or UUID=uuid"
+//usage:#define findfs_full_usage "\n\n"
+//usage: "Find a filesystem device based on a label or UUID"
+//usage:
+//usage:#define findfs_example_usage
+//usage: "$ findfs LABEL=MyDevice"
+
+#include "libbb.h"
+#include "volume_id.h"
+
+int findfs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int findfs_main(int argc UNUSED_PARAM, char **argv)
+{
+ char *dev = *++argv;
+
+ if (!dev)
+ bb_show_usage();
+
+ if (strncmp(dev, "/dev/", 5) == 0) {
+ /* Just pass any /dev/xxx name right through.
+ * This might aid in some scripts being able
+ * to call this unconditionally */
+ dev = NULL;
+ } else {
+ /* Otherwise, handle LABEL=xxx and UUID=xxx,
+ * fail on anything else */
+ if (!resolve_mount_spec(argv))
+ bb_show_usage();
+ }
+
+ if (*argv != dev) {
+ puts(*argv);
+ return 0;
+ }
+ return 1;
+}
diff --git a/ap/app/busybox/src/util-linux/flock.c b/ap/app/busybox/src/util-linux/flock.c
new file mode 100644
index 0000000..05a747f
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/flock.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2010 Timo Teras <timo.teras@iki.fi>
+ *
+ * This is free software, licensed under the GNU General Public License v2.
+ */
+
+//usage:#define flock_trivial_usage
+//usage: "[-sxun] FD|{FILE [-c] PROG ARGS}"
+//usage:#define flock_full_usage "\n\n"
+//usage: "[Un]lock file descriptor, or lock FILE, run PROG\n"
+//usage: "\n -s Shared lock"
+//usage: "\n -x Exclusive lock (default)"
+//usage: "\n -u Unlock FD"
+//usage: "\n -n Fail rather than wait"
+
+#include <sys/file.h>
+#include "libbb.h"
+
+int flock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int flock_main(int argc UNUSED_PARAM, char **argv)
+{
+ int mode, opt, fd;
+ enum {
+ OPT_s = (1 << 0),
+ OPT_x = (1 << 1),
+ OPT_n = (1 << 2),
+ OPT_u = (1 << 3),
+ OPT_c = (1 << 4),
+ };
+
+#if ENABLE_LONG_OPTS
+ static const char getopt_longopts[] ALIGN1 =
+ "shared\0" No_argument "s"
+ "exclusive\0" No_argument "x"
+ "unlock\0" No_argument "u"
+ "nonblock\0" No_argument "n"
+ ;
+ applet_long_options = getopt_longopts;
+#endif
+ opt_complementary = "-1";
+
+ opt = getopt32(argv, "+sxnu");
+ argv += optind;
+
+ if (argv[1]) {
+ fd = open(argv[0], O_RDONLY|O_NOCTTY|O_CREAT, 0666);
+ if (fd < 0 && errno == EISDIR)
+ fd = open(argv[0], O_RDONLY|O_NOCTTY);
+ if (fd < 0)
+ bb_perror_msg_and_die("can't open '%s'", argv[0]);
+ //TODO? close_on_exec_on(fd);
+ } else {
+ fd = xatoi_positive(argv[0]);
+ }
+ argv++;
+
+ /* If it is "flock FILE -c PROG", then -c isn't caught by getopt32:
+ * we use "+" in order to support "flock -opt FILE PROG -with-opts",
+ * we need to remove -c by hand.
+ * TODO: in upstream, -c 'PROG ARGS' means "run sh -c 'PROG ARGS'"
+ */
+ if (argv[0]
+ && argv[0][0] == '-'
+ && ( (argv[0][1] == 'c' && !argv[0][2])
+ || (ENABLE_LONG_OPTS && strcmp(argv[0] + 1, "-command") == 0)
+ )
+ ) {
+ argv++;
+ }
+
+ if (OPT_s == LOCK_SH && OPT_x == LOCK_EX && OPT_n == LOCK_NB && OPT_u == LOCK_UN) {
+ /* With suitably matched constants, mode setting is much simpler */
+ mode = opt & (LOCK_SH + LOCK_EX + LOCK_NB + LOCK_UN);
+ if (!(mode & ~LOCK_NB))
+ mode |= LOCK_EX;
+ } else {
+ if (opt & OPT_u)
+ mode = LOCK_UN;
+ else if (opt & OPT_s)
+ mode = LOCK_SH;
+ else
+ mode = LOCK_EX;
+ if (opt & OPT_n)
+ mode |= LOCK_NB;
+ }
+
+ if (flock(fd, mode) != 0) {
+ if (errno == EWOULDBLOCK)
+ return EXIT_FAILURE;
+ bb_perror_nomsg_and_die();
+ }
+
+ if (argv[0])
+ return spawn_and_wait(argv);
+
+ return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/util-linux/freeramdisk.c b/ap/app/busybox/src/util-linux/freeramdisk.c
new file mode 100644
index 0000000..a89ae1a
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/freeramdisk.c
@@ -0,0 +1,45 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * freeramdisk and fdflush implementations for busybox
+ *
+ * Copyright (C) 2000 and written by Emanuele Caratti <wiz@iol.it>
+ * Adjusted a bit by Erik Andersen <andersen@codepoet.org>
+ * Unified with fdflush by Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//usage:#define freeramdisk_trivial_usage
+//usage: "DEVICE"
+//usage:#define freeramdisk_full_usage "\n\n"
+//usage: "Free all memory used by the specified ramdisk"
+//usage:
+//usage:#define freeramdisk_example_usage
+//usage: "$ freeramdisk /dev/ram2\n"
+//usage:
+//usage:#define fdflush_trivial_usage
+//usage: "DEVICE"
+//usage:#define fdflush_full_usage "\n\n"
+//usage: "Force floppy disk drive to detect disk change"
+
+#include <sys/mount.h>
+#include "libbb.h"
+
+/* From <linux/fd.h> */
+#define FDFLUSH _IO(2,0x4b)
+
+int freeramdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int freeramdisk_main(int argc UNUSED_PARAM, char **argv)
+{
+ int fd;
+
+ fd = xopen(single_argv(argv), O_RDWR);
+
+ // 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]);
+
+ if (ENABLE_FEATURE_CLEAN_UP) close(fd);
+
+ return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/util-linux/fsck_minix.c b/ap/app/busybox/src/util-linux/fsck_minix.c
new file mode 100644
index 0000000..c1d1b2c
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/fsck_minix.c
@@ -0,0 +1,1315 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * fsck.c - a file system consistency checker for Linux.
+ *
+ * (C) 1991, 1992 Linus Torvalds.
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+/*
+ * 09.11.91 - made the first rudimentary functions
+ *
+ * 10.11.91 - updated, does checking, no repairs yet.
+ * Sent out to the mailing-list for testing.
+ *
+ * 14.11.91 - Testing seems to have gone well. Added some
+ * correction-code, and changed some functions.
+ *
+ * 15.11.91 - More correction code. Hopefully it notices most
+ * cases now, and tries to do something about them.
+ *
+ * 16.11.91 - More corrections (thanks to Mika Jalava). Most
+ * things seem to work now. Yeah, sure.
+ *
+ * 19.04.92 - Had to start over again from this old version, as a
+ * kernel bug ate my enhanced fsck in february.
+ *
+ * 28.02.93 - added support for different directory entry sizes..
+ *
+ * Sat Mar 6 18:59:42 1993, faith@cs.unc.edu: Output namelen with
+ * superblock information
+ *
+ * Sat Oct 9 11:17:11 1993, faith@cs.unc.edu: make exit status conform
+ * to that required by fsutil
+ *
+ * Mon Jan 3 11:06:52 1994 - Dr. Wettstein (greg%wind.uucp@plains.nodak.edu)
+ * Added support for file system valid flag. Also
+ * added program_version variable and output of
+ * program name and version number when program
+ * is executed.
+ *
+ * 30.10.94 - added support for v2 filesystem
+ * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
+ *
+ * 10.12.94 - added test to prevent checking of mounted fs adapted
+ * from Theodore Ts'o's (tytso@athena.mit.edu) e2fsck
+ * program. (Daniel Quinlan, quinlan@yggdrasil.com)
+ *
+ * 01.07.96 - Fixed the v2 fs stuff to use the right #defines and such
+ * for modern libcs (janl@math.uio.no, Nicolai Langfeldt)
+ *
+ * 02.07.96 - Added C bit fiddling routines from rmk@ecs.soton.ac.uk
+ * (Russell King). He made them for ARM. It would seem
+ * that the ARM is powerful enough to do this in C whereas
+ * i386 and m64k must use assembly to get it fast >:-)
+ * This should make minix fsck system-independent.
+ * (janl@math.uio.no, Nicolai Langfeldt)
+ *
+ * 04.11.96 - Added minor fixes from Andreas Schwab to avoid compiler
+ * warnings. Added mc68k bitops from
+ * Joerg Dorchain <dorchain@mpi-sb.mpg.de>.
+ *
+ * 06.11.96 - Added v2 code submitted by Joerg Dorchain, but written by
+ * Andreas Schwab.
+ *
+ * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
+ * - added Native Language Support
+ *
+ *
+ * I've had no time to add comments - hopefully the function names
+ * are comments enough. As with all file system checkers, this assumes
+ * the file system is quiescent - don't use it on a mounted device
+ * unless you can be sure nobody is writing to it (and remember that the
+ * kernel can write to it when it searches for files).
+ *
+ * Usage: fsck [-larvsm] device
+ * -l for a listing of all the filenames
+ * -a for automatic repairs (not implemented)
+ * -r for repairs (interactive) (not implemented)
+ * -v for verbose (tells how many files)
+ * -s for 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 :-).
+ */
+
+//usage:#define fsck_minix_trivial_usage
+//usage: "[-larvsmf] BLOCKDEV"
+//usage:#define fsck_minix_full_usage "\n\n"
+//usage: "Check MINIX filesystem\n"
+//usage: "\n -l List all filenames"
+//usage: "\n -r Perform interactive repairs"
+//usage: "\n -a Perform automatic repairs"
+//usage: "\n -v Verbose"
+//usage: "\n -s Output superblock information"
+//usage: "\n -m Show \"mode not cleared\" warnings"
+//usage: "\n -f Force file system check"
+
+#include <mntent.h>
+#include "libbb.h"
+#include "minix.h"
+
+#ifndef BLKGETSIZE
+#define BLKGETSIZE _IO(0x12,96) /* return device size */
+#endif
+
+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
+};
+
+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 */
+};
+
+
+#if !ENABLE_FEATURE_MINIX2
+enum { version2 = 0 };
+#endif
+
+enum { MAX_DEPTH = 32 };
+
+enum { dev_fd = 3 };
+
+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];
+ IF_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];
+};
+#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] = ¤t_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)
+
+#define Super (*(struct minix_superblock *)(superblock_buffer))
+
+#if ENABLE_FEATURE_MINIX2
+# define ZONES ((unsigned)(version2 ? Super.s_zones : Super.s_nzones))
+#else
+# define ZONES ((unsigned)(Super.s_nzones))
+#endif
+#define INODES ((unsigned)Super.s_ninodes)
+#define IMAPS ((unsigned)Super.s_imap_blocks)
+#define ZMAPS ((unsigned)Super.s_zmap_blocks)
+#define FIRSTZONE ((unsigned)Super.s_firstdatazone)
+#define ZONESIZE ((unsigned)Super.s_log_zone_size)
+#define MAXSIZE ((unsigned)Super.s_max_size)
+#define MAGIC (Super.s_magic)
+
+/* gcc likes this more (code is smaller) than macro variant */
+static ALWAYS_INLINE unsigned div_roundup(unsigned size, unsigned n)
+{
+ return (size + n-1) / n;
+}
+
+#if !ENABLE_FEATURE_MINIX2
+#define INODE_BLOCKS div_roundup(INODES, MINIX1_INODES_PER_BLOCK)
+#else
+#define INODE_BLOCKS div_roundup(INODES, \
+ (version2 ? MINIX2_INODES_PER_BLOCK : MINIX1_INODES_PER_BLOCK))
+#endif
+
+#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)));
+}
+
+static void minix_setbit(char *a, unsigned i)
+{
+ setbit(a, i);
+ changed = 1;
+}
+static void minix_clrbit(char *a, unsigned i)
+{
+ clrbit(a, i);
+ changed = 1;
+}
+
+/* Note: do not assume 0/1, it is 0/nonzero */
+#define zone_in_use(x) (minix_bit(zone_map,(x)-FIRSTZONE+1))
+#define inode_in_use(x) (minix_bit(inode_map,(x)))
+
+#define mark_inode(x) (minix_setbit(inode_map,(x)))
+#define unmark_inode(x) (minix_clrbit(inode_map,(x)))
+
+#define mark_zone(x) (minix_setbit(zone_map,(x)-FIRSTZONE+1))
+#define unmark_zone(x) (minix_clrbit(zone_map,(x)-FIRSTZONE+1))
+
+
+static void recursive_check(unsigned ino);
+#if ENABLE_FEATURE_MINIX2
+static void recursive_check2(unsigned ino);
+#endif
+
+static void die(const char *str) NORETURN;
+static void die(const char *str)
+{
+ if (termios_set)
+ tcsetattr_stdin_TCSANOW(&sv_termios);
+ bb_error_msg_and_die("%s", str);
+}
+
+static void push_filename(const char *name)
+{
+ // /dir/dir/dir/file
+ // ^ ^ ^
+ // [0] [1] [2] <-name_component[i]
+ if (name_depth < MAX_DEPTH) {
+ int len;
+ char *p = name_component[name_depth];
+ *p++ = '/';
+ len = sprintf(p, "%.*s", namelen, name);
+ name_component[name_depth + 1] = p + len;
+ }
+ name_depth++;
+}
+
+static void pop_filename(void)
+{
+ name_depth--;
+ if (name_depth < MAX_DEPTH) {
+ *name_component[name_depth] = '\0';
+ if (!name_depth) {
+ current_name[0] = '/';
+ current_name[1] = '\0';
+ }
+ }
+}
+
+static int ask(const char *string, int def)
+{
+ int c;
+
+ if (!OPT_repair) {
+ bb_putchar('\n');
+ errors_uncorrected = 1;
+ return 0;
+ }
+ if (OPT_automatic) {
+ bb_putchar('\n');
+ if (!def)
+ errors_uncorrected = 1;
+ return def;
+ }
+ printf(def ? "%s (y/n)? " : "%s (n/y)? ", string);
+ for (;;) {
+ fflush_all();
+ c = getchar();
+ if (c == EOF) {
+ if (!def)
+ errors_uncorrected = 1;
+ return def;
+ }
+ if (c == '\n')
+ break;
+ c |= 0x20; /* tolower */
+ if (c == 'y') {
+ def = 1;
+ break;
+ }
+ if (c == 'n') {
+ def = 0;
+ break;
+ }
+ }
+ if (def)
+ printf("y\n");
+ else {
+ printf("n\n");
+ errors_uncorrected = 1;
+ }
+ return def;
+}
+
+/*
+ * Make certain that we aren't checking a filesystem that is on a
+ * mounted partition. Code adapted from e2fsck, Copyright (C) 1993,
+ * 1994 Theodore Ts'o. Also licensed under GPL.
+ */
+static void check_mount(void)
+{
+ if (find_mount_point(device_name, 0)) {
+ int cont;
+#if ENABLE_FEATURE_MTAB_SUPPORT
+ /*
+ * If the root is mounted read-only, then /etc/mtab is
+ * probably not correct; so we won't issue a warning based on
+ * it.
+ */
+ int fd = open(bb_path_mtab_file, O_RDWR);
+
+ if (fd < 0 && errno == EROFS)
+ return;
+ close(fd);
+#endif
+ printf("%s is mounted. ", device_name);
+ cont = 0;
+ if (isatty(0) && isatty(1))
+ cont = ask("Do you really want to continue", 0);
+ if (!cont) {
+ printf("Check aborted\n");
+ exit(EXIT_SUCCESS);
+ }
+ }
+}
+
+/*
+ * check_zone_nr checks to see that *nr is a valid zone nr. If it
+ * isn't, it will possibly be repaired. Check_zone_nr sets *corrected
+ * if an error was corrected, and returns the zone (0 for no zone
+ * or a bad zone-number).
+ */
+static int check_zone_nr2(uint32_t *nr, smallint *corrected)
+{
+ const char *msg;
+ if (!*nr)
+ return 0;
+ if (*nr < FIRSTZONE)
+ msg = "< FIRSTZONE";
+ else if (*nr >= ZONES)
+ msg = ">= ZONES";
+ else
+ return *nr;
+ printf("Zone nr %s in file '%s'. ", msg, current_name);
+ if (ask("Remove block", 1)) {
+ *nr = 0;
+ *corrected = 1;
+ }
+ return 0;
+}
+
+static int check_zone_nr(uint16_t *nr, smallint *corrected)
+{
+ uint32_t nr32 = *nr;
+ int r = check_zone_nr2(&nr32, corrected);
+ *nr = (uint16_t)nr32;
+ return r;
+}
+
+/*
+ * read-block reads block nr into the buffer at addr.
+ */
+static void read_block(unsigned nr, void *addr)
+{
+ if (!nr) {
+ memset(addr, 0, BLOCK_SIZE);
+ return;
+ }
+ 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;
+ memset(addr, 0, BLOCK_SIZE);
+ }
+}
+
+/*
+ * write_block writes block nr to disk.
+ */
+static void write_block(unsigned nr, void *addr)
+{
+ if (!nr)
+ return;
+ if (nr < FIRSTZONE || nr >= ZONES) {
+ printf("Internal error: trying to write bad block\n"
+ "Write request ignored\n");
+ errors_uncorrected = 1;
+ return;
+ }
+ 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.
+ * It sets 'changed' if the inode has needed changing, and re-writes
+ * any indirect blocks with errors.
+ */
+static int map_block(struct minix1_inode *inode, unsigned blknr)
+{
+ uint16_t ind[BLOCK_SIZE >> 1];
+ 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);
+ goto common;
+ }
+ blknr -= 512;
+ block = check_zone_nr(inode->i_zone + 8, &changed);
+ read_block(block, ind); /* double indirect */
+ blk_chg = 0;
+ result = check_zone_nr(&ind[blknr / 512], &blk_chg);
+ if (blk_chg)
+ write_block(block, ind);
+ block = result;
+ common:
+ read_block(block, ind);
+ blk_chg = 0;
+ result = check_zone_nr(&ind[blknr % 512], &blk_chg);
+ if (blk_chg)
+ write_block(block, ind);
+ return result;
+}
+
+#if ENABLE_FEATURE_MINIX2
+static int map_block2(struct minix2_inode *inode, unsigned blknr)
+{
+ 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);
+ goto common2;
+ }
+ blknr -= 256;
+ if (blknr < 256 * 256) {
+ block = check_zone_nr2(inode->i_zone + 8, &changed);
+ goto common1;
+ }
+ blknr -= 256 * 256;
+ block = check_zone_nr2(inode->i_zone + 9, &changed);
+ read_block(block, ind); /* triple indirect */
+ blk_chg = 0;
+ result = check_zone_nr2(&ind[blknr / (256 * 256)], &blk_chg);
+ if (blk_chg)
+ write_block(block, ind);
+ block = result;
+ common1:
+ read_block(block, ind); /* double indirect */
+ blk_chg = 0;
+ result = check_zone_nr2(&ind[(blknr / 256) % 256], &blk_chg);
+ if (blk_chg)
+ write_block(block, ind);
+ block = result;
+ common2:
+ read_block(block, ind);
+ blk_chg = 0;
+ result = check_zone_nr2(&ind[blknr % 256], &blk_chg);
+ if (blk_chg)
+ write_block(block, ind);
+ return result;
+}
+#endif
+
+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 | MINIX_ERROR_FS;
+ if (!errors_uncorrected)
+ Super.s_state &= ~MINIX_ERROR_FS;
+
+ xlseek(dev_fd, BLOCK_SIZE, SEEK_SET);
+ if (BLOCK_SIZE != full_write(dev_fd, superblock_buffer, BLOCK_SIZE))
+ die("can't write superblock");
+}
+
+static void write_tables(void)
+{
+ write_superblock();
+
+ if (IMAPS * BLOCK_SIZE != write(dev_fd, inode_map, IMAPS * BLOCK_SIZE))
+ die("can't write inode map");
+ if (ZMAPS * BLOCK_SIZE != write(dev_fd, zone_map, ZMAPS * BLOCK_SIZE))
+ die("can't write zone map");
+ if (INODE_BUFFER_SIZE != write(dev_fd, inode_buffer, INODE_BUFFER_SIZE))
+ die("can't write inodes");
+}
+
+static void get_dirsize(void)
+{
+ int block;
+ char blk[BLOCK_SIZE];
+ int size;
+
+#if ENABLE_FEATURE_MINIX2
+ if (version2)
+ block = Inode2[MINIX_ROOT_INO].i_zone[0];
+ else
+#endif
+ block = Inode1[MINIX_ROOT_INO].i_zone[0];
+ read_block(block, blk);
+ for (size = 16; size < BLOCK_SIZE; size <<= 1) {
+ if (strcmp(blk + size + 2, "..") == 0) {
+ dirsize = size;
+ namelen = size - 2;
+ return;
+ }
+ }
+ /* use defaults */
+}
+
+static void read_superblock(void)
+{
+ xlseek(dev_fd, BLOCK_SIZE, SEEK_SET);
+ if (BLOCK_SIZE != full_read(dev_fd, superblock_buffer, BLOCK_SIZE))
+ die("can't 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;
+#if ENABLE_FEATURE_MINIX2
+ } else if (MAGIC == MINIX2_SUPER_MAGIC) {
+ version2 = 1;
+ } else if (MAGIC == MINIX2_SUPER_MAGIC2) {
+ namelen = 30;
+ dirsize = 32;
+ version2 = 1;
+#endif
+ } else
+ die("bad magic number in superblock");
+ if (ZONESIZE != 0 || BLOCK_SIZE != 1024)
+ die("only 1k blocks/zones supported");
+ if (IMAPS * BLOCK_SIZE * 8 < INODES + 1)
+ die("bad s_imap_blocks field in superblock");
+ if (ZMAPS * BLOCK_SIZE * 8 < ZONES - FIRSTZONE + 1)
+ die("bad s_zmap_blocks field in superblock");
+}
+
+static void read_tables(void)
+{
+ inode_map = xzalloc(IMAPS * BLOCK_SIZE);
+ zone_map = xzalloc(ZMAPS * BLOCK_SIZE);
+ inode_buffer = xmalloc(INODE_BUFFER_SIZE);
+ inode_count = xmalloc(INODES + 1);
+ zone_count = xmalloc(ZONES);
+ if (IMAPS * BLOCK_SIZE != read(dev_fd, inode_map, IMAPS * BLOCK_SIZE))
+ die("can't read inode map");
+ if (ZMAPS * BLOCK_SIZE != read(dev_fd, zone_map, ZMAPS * BLOCK_SIZE))
+ die("can't read zone map");
+ if (INODE_BUFFER_SIZE != read(dev_fd, inode_buffer, INODE_BUFFER_SIZE))
+ die("can't read inodes");
+ if (NORM_FIRSTZONE != FIRSTZONE) {
+ printf("warning: firstzone!=norm_firstzone\n");
+ errors_uncorrected = 1;
+ }
+ get_dirsize();
+ 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 void get_inode_common(unsigned nr, uint16_t i_mode)
+{
+ total++;
+ if (!inode_count[nr]) {
+ if (!inode_in_use(nr)) {
+ printf("Inode %d is marked as 'unused', but it is used "
+ "for file '%s'\n", nr, current_name);
+ if (OPT_repair) {
+ if (ask("Mark as 'in use'", 1))
+ mark_inode(nr);
+ else
+ errors_uncorrected = 1;
+ }
+ }
+ if (S_ISDIR(i_mode))
+ directory++;
+ else if (S_ISREG(i_mode))
+ regular++;
+ else if (S_ISCHR(i_mode))
+ chardev++;
+ else if (S_ISBLK(i_mode))
+ blockdev++;
+ else if (S_ISLNK(i_mode))
+ symlinks++;
+ else if (S_ISSOCK(i_mode));
+ else if (S_ISFIFO(i_mode));
+ else {
+ printf("%s has mode %05o\n", current_name, i_mode);
+ }
+ } else
+ links++;
+ if (!++inode_count[nr]) {
+ 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;
+}
+
+#if ENABLE_FEATURE_MINIX2
+static struct minix2_inode *get_inode2(unsigned nr)
+{
+ struct minix2_inode *inode;
+
+ if (!nr || nr > INODES)
+ return NULL;
+ inode = Inode2 + nr;
+ get_inode_common(nr, inode->i_mode);
+ return inode;
+}
+#endif
+
+static void check_root(void)
+{
+ struct minix1_inode *inode = Inode1 + MINIX_ROOT_INO;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ die("root inode isn't a directory");
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void check_root2(void)
+{
+ struct minix2_inode *inode = Inode2 + MINIX_ROOT_INO;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ die("root inode isn't a directory");
+}
+#else
+void check_root2(void);
+#endif
+
+static int add_zone_common(int block, smallint *corrected)
+{
+ if (!block)
+ return 0;
+ if (zone_count[block]) {
+ printf("Already used block is reused in file '%s'. ",
+ current_name);
+ if (ask("Clear", 1)) {
+ block = 0;
+ *corrected = 1;
+ return -1; /* "please zero out *znr" */
+ }
+ }
+ if (!zone_in_use(block)) {
+ printf("Block %d in file '%s' is marked as 'unused'. ",
+ block, current_name);
+ if (ask("Correct", 1))
+ mark_zone(block);
+ }
+ if (!++zone_count[block])
+ zone_count[block]--;
+ return block;
+}
+
+static int add_zone(uint16_t *znr, smallint *corrected)
+{
+ int block;
+
+ block = check_zone_nr(znr, corrected);
+ block = add_zone_common(block, corrected);
+ if (block == -1) {
+ *znr = 0;
+ block = 0;
+ }
+ 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;
+ }
+ return block;
+}
+#endif
+
+static void add_zone_ind(uint16_t *znr, smallint *corrected)
+{
+ int i;
+ int block;
+ smallint chg_blk = 0;
+
+ block = add_zone(znr, corrected);
+ if (!block)
+ return;
+ read_block(block, add_zone_ind_blk);
+ for (i = 0; i < (BLOCK_SIZE >> 1); i++)
+ add_zone(i + (uint16_t *) add_zone_ind_blk, &chg_blk);
+ if (chg_blk)
+ write_block(block, add_zone_ind_blk);
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void add_zone_ind2(uint32_t *znr, smallint *corrected)
+{
+ int i;
+ int block;
+ smallint chg_blk = 0;
+
+ block = add_zone2(znr, corrected);
+ if (!block)
+ return;
+ read_block(block, add_zone_ind_blk);
+ for (i = 0; i < BLOCK_SIZE >> 2; i++)
+ add_zone2(i + (uint32_t *) add_zone_ind_blk, &chg_blk);
+ if (chg_blk)
+ write_block(block, add_zone_ind_blk);
+}
+#endif
+
+static void add_zone_dind(uint16_t *znr, smallint *corrected)
+{
+ int i;
+ int block;
+ smallint chg_blk = 0;
+
+ block = add_zone(znr, corrected);
+ if (!block)
+ return;
+ read_block(block, add_zone_dind_blk);
+ for (i = 0; i < (BLOCK_SIZE >> 1); i++)
+ add_zone_ind(i + (uint16_t *) add_zone_dind_blk, &chg_blk);
+ if (chg_blk)
+ write_block(block, add_zone_dind_blk);
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void add_zone_dind2(uint32_t *znr, smallint *corrected)
+{
+ int i;
+ int block;
+ smallint chg_blk = 0;
+
+ block = add_zone2(znr, corrected);
+ if (!block)
+ return;
+ read_block(block, add_zone_dind_blk);
+ for (i = 0; i < BLOCK_SIZE >> 2; i++)
+ 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(uint32_t *znr, smallint *corrected)
+{
+ int i;
+ int block;
+ smallint chg_blk = 0;
+
+ block = add_zone2(znr, corrected);
+ if (!block)
+ return;
+ read_block(block, add_zone_tind_blk);
+ for (i = 0; i < BLOCK_SIZE >> 2; i++)
+ 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 i)
+{
+ struct minix1_inode *inode;
+
+ if (!i || i > INODES)
+ return;
+ if (inode_count[i] > 1) /* have we counted this file already? */
+ return;
+ inode = Inode1 + i;
+ if (!S_ISDIR(inode->i_mode)
+ && !S_ISREG(inode->i_mode)
+ && !S_ISLNK(inode->i_mode)
+ ) {
+ return;
+ }
+ for (i = 0; i < 7; i++)
+ add_zone(i + inode->i_zone, &changed);
+ add_zone_ind(7 + inode->i_zone, &changed);
+ add_zone_dind(8 + inode->i_zone, &changed);
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void check_zones2(unsigned i)
+{
+ struct minix2_inode *inode;
+
+ if (!i || i > INODES)
+ return;
+ if (inode_count[i] > 1) /* have we counted this file already? */
+ return;
+ inode = Inode2 + i;
+ if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode)
+ && !S_ISLNK(inode->i_mode))
+ return;
+ for (i = 0; i < 7; i++)
+ add_zone2(i + inode->i_zone, &changed);
+ add_zone_ind2(7 + inode->i_zone, &changed);
+ add_zone_dind2(8 + inode->i_zone, &changed);
+ add_zone_tind2(9 + inode->i_zone, &changed);
+}
+#endif
+
+static void check_file(struct minix1_inode *dir, unsigned offset)
+{
+ struct minix1_inode *inode;
+ int ino;
+ char *name;
+ int block;
+
+ block = map_block(dir, offset / BLOCK_SIZE);
+ read_block(block, check_file_blk);
+ name = check_file_blk + (offset % BLOCK_SIZE) + 2;
+ ino = *(uint16_t *) (name - 2);
+ if (ino > INODES) {
+ printf("%s contains a bad inode number for file '%.*s'. ",
+ current_name, namelen, name);
+ if (ask("Remove", 1)) {
+ *(uint16_t *) (name - 2) = 0;
+ write_block(block, check_file_blk);
+ }
+ ino = 0;
+ }
+ push_filename(name);
+ inode = get_inode(ino);
+ pop_filename();
+ if (!offset) {
+ if (inode && LONE_CHAR(name, '.'))
+ return;
+ printf("%s: bad directory: '.' isn't first\n", current_name);
+ errors_uncorrected = 1;
+ }
+ if (offset == dirsize) {
+ if (inode && strcmp("..", name) == 0)
+ return;
+ printf("%s: bad directory: '..' isn't second\n", current_name);
+ errors_uncorrected = 1;
+ }
+ if (!inode)
+ return;
+ push_filename(name);
+ if (OPT_list) {
+ if (OPT_verbose)
+ printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
+ printf("%s%s\n", current_name, S_ISDIR(inode->i_mode) ? ":" : "");
+ }
+ check_zones(ino);
+ if (inode && S_ISDIR(inode->i_mode))
+ recursive_check(ino);
+ pop_filename();
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void check_file2(struct minix2_inode *dir, unsigned offset)
+{
+ struct minix2_inode *inode;
+ int ino;
+ char *name;
+ int block;
+
+ block = map_block2(dir, offset / BLOCK_SIZE);
+ read_block(block, check_file_blk);
+ name = check_file_blk + (offset % BLOCK_SIZE) + 2;
+ ino = *(uint16_t *) (name - 2);
+ if (ino > INODES) {
+ printf("%s contains a bad inode number for file '%.*s'. ",
+ current_name, namelen, name);
+ if (ask("Remove", 1)) {
+ *(uint16_t *) (name - 2) = 0;
+ write_block(block, check_file_blk);
+ }
+ ino = 0;
+ }
+ push_filename(name);
+ inode = get_inode2(ino);
+ pop_filename();
+ if (!offset) {
+ if (inode && LONE_CHAR(name, '.'))
+ return;
+ printf("%s: bad directory: '.' isn't first\n", current_name);
+ errors_uncorrected = 1;
+ }
+ if (offset == dirsize) {
+ if (inode && strcmp("..", name) == 0)
+ return;
+ printf("%s: bad directory: '..' isn't second\n", current_name);
+ errors_uncorrected = 1;
+ }
+ if (!inode)
+ return;
+ push_filename(name);
+ if (OPT_list) {
+ if (OPT_verbose)
+ printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
+ printf("%s%s\n", current_name, S_ISDIR(inode->i_mode) ? ":" : "");
+ }
+ check_zones2(ino);
+ if (inode && S_ISDIR(inode->i_mode))
+ recursive_check2(ino);
+ pop_filename();
+}
+#endif
+
+static void recursive_check(unsigned ino)
+{
+ struct minix1_inode *dir;
+ unsigned offset;
+
+ dir = Inode1 + ino;
+ if (!S_ISDIR(dir->i_mode))
+ die("internal error");
+ if (dir->i_size < 2 * dirsize) {
+ printf("%s: bad directory: size<32", current_name);
+ errors_uncorrected = 1;
+ }
+ for (offset = 0; offset < dir->i_size; offset += dirsize)
+ check_file(dir, offset);
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void recursive_check2(unsigned ino)
+{
+ struct minix2_inode *dir;
+ unsigned offset;
+
+ dir = Inode2 + ino;
+ if (!S_ISDIR(dir->i_mode))
+ die("internal error");
+ if (dir->i_size < 2 * dirsize) {
+ printf("%s: bad directory: size<32", current_name);
+ errors_uncorrected = 1;
+ }
+ for (offset = 0; offset < dir->i_size; offset += dirsize)
+ check_file2(dir, offset);
+}
+#endif
+
+static int bad_zone(int i)
+{
+ char buffer[BLOCK_SIZE];
+
+ xlseek(dev_fd, BLOCK_SIZE * i, SEEK_SET);
+ return (BLOCK_SIZE != full_read(dev_fd, buffer, BLOCK_SIZE));
+}
+
+static void check_counts(void)
+{
+ int i;
+
+ for (i = 1; i <= INODES; 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)) {
+ Inode1[i].i_mode = 0;
+ changed = 1;
+ }
+ }
+ if (!inode_count[i]) {
+ if (!inode_in_use(i))
+ continue;
+ printf("Unused inode %d is marked as 'used' in the bitmap. ", i);
+ if (ask("Clear", 1))
+ unmark_inode(i);
+ continue;
+ }
+ if (!inode_in_use(i)) {
+ printf("Inode %d is used, but marked as 'unused' in the bitmap. ", i);
+ if (ask("Set", 1))
+ mark_inode(i);
+ }
+ if (Inode1[i].i_nlinks != inode_count[i]) {
+ printf("Inode %d (mode=%07o), i_nlinks=%d, counted=%d. ",
+ i, Inode1[i].i_mode, Inode1[i].i_nlinks,
+ inode_count[i]);
+ if (ask("Set i_nlinks to count", 1)) {
+ Inode1[i].i_nlinks = inode_count[i];
+ changed = 1;
+ }
+ }
+ }
+ for (i = FIRSTZONE; i < ZONES; i++) {
+ if ((zone_in_use(i) != 0) == zone_count[i])
+ continue;
+ if (!zone_count[i]) {
+ if (bad_zone(i))
+ continue;
+ printf("Zone %d is marked 'in use', but no file uses it. ", i);
+ if (ask("Unmark", 1))
+ unmark_zone(i);
+ continue;
+ }
+ printf("Zone %d: %sin use, counted=%d\n",
+ i, zone_in_use(i) ? "" : "not ", zone_count[i]);
+ }
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void check_counts2(void)
+{
+ int i;
+
+ for (i = 1; i <= INODES; i++) {
+ if (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;
+ }
+ }
+ if (!inode_count[i]) {
+ if (!inode_in_use(i))
+ continue;
+ printf("Unused inode %d is marked as 'used' in the bitmap. ", i);
+ if (ask("Clear", 1))
+ unmark_inode(i);
+ continue;
+ }
+ if (!inode_in_use(i)) {
+ printf("Inode %d is used, but marked as 'unused' in the bitmap. ", i);
+ if (ask("Set", 1))
+ mark_inode(i);
+ }
+ if (Inode2[i].i_nlinks != inode_count[i]) {
+ printf("Inode %d (mode=%07o), i_nlinks=%d, counted=%d. ",
+ i, Inode2[i].i_mode, Inode2[i].i_nlinks,
+ inode_count[i]);
+ if (ask("Set i_nlinks to count", 1)) {
+ Inode2[i].i_nlinks = inode_count[i];
+ changed = 1;
+ }
+ }
+ }
+ for (i = FIRSTZONE; i < ZONES; i++) {
+ if ((zone_in_use(i) != 0) == zone_count[i])
+ continue;
+ if (!zone_count[i]) {
+ if (bad_zone(i))
+ continue;
+ printf("Zone %d is marked 'in use', but no file uses it. ", i);
+ if (ask("Unmark", 1))
+ unmark_zone(i);
+ continue;
+ }
+ printf("Zone %d: %sin use, counted=%d\n",
+ i, zone_in_use(i) ? "" : "not ", zone_count[i]);
+ }
+}
+#endif
+
+static void check(void)
+{
+ memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
+ memset(zone_count, 0, ZONES * sizeof(*zone_count));
+ check_zones(MINIX_ROOT_INO);
+ recursive_check(MINIX_ROOT_INO);
+ check_counts();
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void check2(void)
+{
+ memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
+ memset(zone_count, 0, ZONES * sizeof(*zone_count));
+ check_zones2(MINIX_ROOT_INO);
+ recursive_check2(MINIX_ROOT_INO);
+ check_counts2();
+}
+#else
+void check2(void);
+#endif
+
+int fsck_minix_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int fsck_minix_main(int argc UNUSED_PARAM, char **argv)
+{
+ struct termios tmp;
+ int retcode = 0;
+
+ xfunc_error_retval = 8;
+
+ 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");
+ }
+ 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
+ * command line.
+ */
+ 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 (OPT_manual) {
+ tcgetattr(0, &sv_termios);
+ tmp = sv_termios;
+ tmp.c_lflag &= ~(ICANON | ECHO);
+ tcsetattr_stdin_TCSANOW(&tmp);
+ termios_set = 1;
+ }
+
+ if (version2) {
+ check_root2();
+ check2();
+ } else {
+ check_root();
+ check();
+ }
+
+ 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%6u inodes used (%u%%)\n", (INODES - free_cnt),
+ 100 * (INODES - free_cnt) / INODES);
+ for (i = FIRSTZONE, free_cnt = 0; i < ZONES; i++)
+ if (!zone_in_use(i))
+ free_cnt++;
+ printf("%6u zones used (%u%%)\n\n"
+ "%6u regular files\n"
+ "%6u directories\n"
+ "%6u character device files\n"
+ "%6u block device files\n"
+ "%6u links\n"
+ "%6u symbolic links\n"
+ "------\n"
+ "%6u files\n",
+ (ZONES - free_cnt), 100 * (ZONES - free_cnt) / ZONES,
+ regular, directory, chardev, blockdev,
+ links - 2 * directory + 1, symlinks,
+ total - 2 * directory + 1);
+ }
+ if (changed) {
+ write_tables();
+ printf("FILE SYSTEM HAS BEEN CHANGED\n");
+ sync();
+ } else if (OPT_repair)
+ write_superblock();
+
+ if (OPT_manual)
+ tcsetattr_stdin_TCSANOW(&sv_termios);
+
+ if (changed)
+ retcode += 3;
+ if (errors_uncorrected)
+ retcode += 4;
+ return retcode;
+}
diff --git a/ap/app/busybox/src/util-linux/getopt.c b/ap/app/busybox/src/util-linux/getopt.c
new file mode 100644
index 0000000..1ae0c59
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/getopt.c
@@ -0,0 +1,422 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * getopt.c - Enhanced implementation of BSD getopt(1)
+ * Copyright (c) 1997, 1998, 1999, 2000 Frodo Looijaard <frodol@dds.nl>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/*
+ * Version 1.0-b4: Tue Sep 23 1997. First public release.
+ * Version 1.0: Wed Nov 19 1997.
+ * Bumped up the version number to 1.0
+ * Fixed minor typo (CSH instead of TCSH)
+ * Version 1.0.1: Tue Jun 3 1998
+ * Fixed sizeof instead of strlen bug
+ * Bumped up the version number to 1.0.1
+ * Version 1.0.2: Thu Jun 11 1998 (not present)
+ * Fixed gcc-2.8.1 warnings
+ * Fixed --version/-V option (not present)
+ * Version 1.0.5: Tue Jun 22 1999
+ * Make -u option work (not present)
+ * Version 1.0.6: Tue Jun 27 2000
+ * No important changes
+ * Version 1.1.0: Tue Jun 30 2000
+ * Added NLS support (partly written by Arkadiusz Mickiewicz
+ * <misiek@misiek.eu.org>)
+ * Ported to Busybox - Alfred M. Szmidt <ams@trillian.itslinux.org>
+ * Removed --version/-V and --help/-h
+ * Removed parse_error(), using bb_error_msg() from Busybox instead
+ * Replaced our_malloc with xmalloc and our_realloc with xrealloc
+ *
+ */
+
+//usage:#define getopt_trivial_usage
+//usage: "[OPTIONS] [--] OPTSTRING PARAMS"
+//usage:#define getopt_full_usage "\n\n"
+//usage: IF_LONG_OPTS(
+//usage: " -a,--alternative Allow long options starting with single -"
+//usage: "\n -l,--longoptions=LOPT[,...] Long options to be recognized"
+//usage: "\n -n,--name=PROGNAME The name under which errors are reported"
+//usage: "\n -o,--options=OPTSTRING Short options to be recognized"
+//usage: "\n -q,--quiet Disable error reporting by getopt(3)"
+//usage: "\n -Q,--quiet-output No normal output"
+//usage: "\n -s,--shell=SHELL Set shell quoting conventions"
+//usage: "\n -T,--test Test for getopt(1) version"
+//usage: "\n -u,--unquoted Don't quote the output"
+//usage: )
+//usage: IF_NOT_LONG_OPTS(
+//usage: " -a Allow long options starting with single -"
+//usage: "\n -l LOPT[,...] Long options to be recognized"
+//usage: "\n -n PROGNAME The name under which errors are reported"
+//usage: "\n -o OPTSTRING Short options to be recognized"
+//usage: "\n -q Disable error reporting by getopt(3)"
+//usage: "\n -Q No normal output"
+//usage: "\n -s SHELL Set shell quoting conventions"
+//usage: "\n -T Test for getopt(1) version"
+//usage: "\n -u Don't quote the output"
+//usage: )
+//usage: "\n"
+//usage: "\nExample:"
+//usage: "\n"
+//usage: "\nO=`getopt -l bb: -- ab:c:: \"$@\"` || exit 1"
+//usage: "\neval set -- \"$O\""
+//usage: "\nwhile true; do"
+//usage: "\n case \"$1\" in"
+//usage: "\n -a) echo A; shift;;"
+//usage: "\n -b|--bb) echo \"B:'$2'\"; shift 2;;"
+//usage: "\n -c) case \"$2\" in"
+//usage: "\n \"\") echo C; shift 2;;"
+//usage: "\n *) echo \"C:'$2'\"; shift 2;;"
+//usage: "\n esac;;"
+//usage: "\n --) shift; break;;"
+//usage: "\n *) echo Error; exit 1;;"
+//usage: "\n esac"
+//usage: "\ndone"
+//usage:
+//usage:#define getopt_example_usage
+//usage: "$ cat getopt.test\n"
+//usage: "#!/bin/sh\n"
+//usage: "GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \\\n"
+//usage: " -n 'example.busybox' -- \"$@\"`\n"
+//usage: "if [ $? != 0 ]; then exit 1; fi\n"
+//usage: "eval set -- \"$GETOPT\"\n"
+//usage: "while true; do\n"
+//usage: " case $1 in\n"
+//usage: " -a|--a-long) echo \"Option a\"; shift;;\n"
+//usage: " -b|--b-long) echo \"Option b, argument '$2'\"; shift 2;;\n"
+//usage: " -c|--c-long)\n"
+//usage: " case \"$2\" in\n"
+//usage: " \"\") echo \"Option c, no argument\"; shift 2;;\n"
+//usage: " *) echo \"Option c, argument '$2'\"; shift 2;;\n"
+//usage: " esac;;\n"
+//usage: " --) shift; break;;\n"
+//usage: " *) echo \"Internal error!\"; exit 1;;\n"
+//usage: " esac\n"
+//usage: "done\n"
+
+#if ENABLE_FEATURE_GETOPT_LONG
+# include <getopt.h>
+#endif
+#include "libbb.h"
+
+/* NON_OPT is the code that is returned when a non-option is found in '+'
+ mode */
+enum {
+ NON_OPT = 1,
+#if ENABLE_FEATURE_GETOPT_LONG
+/* LONG_OPT is the code that is returned when a long option is found. */
+ LONG_OPT = 2
+#endif
+};
+
+/* 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_FEATURE_GETOPT_LONG
+ OPT_a = 0x80, // -a
+ OPT_l = 0x100, // -l
+#endif
+ SHELL_IS_TCSH = 0x8000, /* hijack this bit for other purposes */
+};
+
+/* 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
+ * it and escapes other special characters. If quote is false, it just
+ * returns its argument.
+ * Bash only needs special treatment for single quotes; tcsh also recognizes
+ * exclamation marks within single quotes, and nukes whitespace.
+ * This function returns a pointer to a buffer that is overwritten by
+ * each call.
+ */
+static const char *normalize(const char *arg)
+{
+ 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;
+}
+
+/*
+ * Generate the output. argv[0] is the program name (used for reporting errors).
+ * argv[1..] contains the options to be parsed. argc must be the number of
+ * elements in argv (ie. 1 if there are no options, only the program name),
+ * optstr must contain the short options, and longopts the long options.
+ * Other settings are found in global variables.
+ */
+#if !ENABLE_FEATURE_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;
+#if ENABLE_FEATURE_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_FEATURE_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_FEATURE_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;
+}
+
+#if ENABLE_FEATURE_GETOPT_LONG
+/*
+ * Register several long options. options is a string of long options,
+ * separated by commas or whitespace.
+ * This nukes options!
+ */
+static struct option *add_long_options(struct option *long_options, char *options)
+{
+ 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
+
+static void set_shell(const char *new_shell)
+{
+ 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, 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
+ */
+
+#if ENABLE_FEATURE_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)
+{
+ int n;
+ char *optstr = NULL;
+ char *name = NULL;
+ unsigned opt;
+ const char *compatible;
+ char *s_arg;
+#if ENABLE_FEATURE_GETOPT_LONG
+ struct option *long_options = NULL;
+ llist_t *l_arg = NULL;
+#endif
+
+ compatible = getenv("GETOPT_COMPATIBLE"); /* used as yes/no flag */
+
+ if (!argv[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 = argv[1];
+
+ option_mask32 |= OPT_u; /* quoting off */
+ s = xstrdup(s + strspn(s, "-+"));
+ argv[1] = argv[0];
+ return generate_output(argv+1, argc-1, s, long_options);
+ }
+
+#if !ENABLE_FEATURE_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 */
+ n = optind - 1;
+ if (!optstr) {
+ optstr = argv[++n];
+ if (!optstr)
+ bb_error_msg_and_die("missing optstring argument");
+ }
+
+ argv[n] = name ? name : argv[0];
+ return generate_output(argv + n, argc - n, optstr, long_options);
+}
diff --git a/ap/app/busybox/src/util-linux/hexdump.c b/ap/app/busybox/src/util-linux/hexdump.c
new file mode 100644
index 0000000..9a312f9
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/hexdump.c
@@ -0,0 +1,174 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * hexdump implementation for busybox
+ * Based on code from util-linux v 2.11l
+ *
+ * Copyright (c) 1989
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+//usage:#define hexdump_trivial_usage
+//usage: "[-bcCdefnosvx" IF_FEATURE_HEXDUMP_REVERSE("R") "] [FILE]..."
+//usage:#define hexdump_full_usage "\n\n"
+//usage: "Display FILEs (or stdin) in a user specified format\n"
+//usage: "\n -b One-byte octal display"
+//usage: "\n -c One-byte character display"
+//usage: "\n -C Canonical hex+ASCII, 16 bytes per line"
+//usage: "\n -d Two-byte decimal display"
+//usage: "\n -e FORMAT_STRING"
+//usage: "\n -f FORMAT_FILE"
+//usage: "\n -n LENGTH Interpret only LENGTH bytes of input"
+//usage: "\n -o Two-byte octal display"
+//usage: "\n -s OFFSET Skip OFFSET bytes"
+//usage: "\n -v Display all input data"
+//usage: "\n -x Two-byte hexadecimal display"
+//usage: IF_FEATURE_HEXDUMP_REVERSE(
+//usage: "\n -R Reverse of 'hexdump -Cv'")
+//usage:
+//usage:#define hd_trivial_usage
+//usage: "FILE..."
+//usage:#define hd_full_usage "\n\n"
+//usage: "hd is an alias for hexdump -C"
+
+#include "libbb.h"
+#include "dump.h"
+
+/* This is a NOEXEC applet. Be very careful! */
+
+static void bb_dump_addfile(dumper_t *dumper, char *name)
+{
+ char *p;
+ FILE *fp;
+ char *buf;
+
+ fp = xfopen_for_read(name);
+ while ((buf = xmalloc_fgetline(fp)) != NULL) {
+ p = skip_whitespace(buf);
+ if (*p && (*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 add_first[] ALIGN1 = "\"%07.7_Ax\n\"";
+
+static const char hexdump_opts[] ALIGN1 = "bcdoxCe:f:n:s:v" IF_FEATURE_HEXDUMP_REVERSE("R");
+
+static const struct suffix_mult suffixes[] = {
+ { "b", 512 },
+ { "k", 1024 },
+ { "m", 1024*1024 },
+ { "", 0 }
+};
+
+int hexdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int hexdump_main(int argc, char **argv)
+{
+ dumper_t *dumper = alloc_dumper();
+ const char *p;
+ int ch;
+#if ENABLE_FEATURE_HEXDUMP_REVERSE
+ FILE *fp;
+ smallint rdump = 0;
+#endif
+
+ 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) {
+ 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_positive(optarg);
+ } /* else */
+ if (ch == 's') { /* compat: -s accepts hex numbers too */
+ dumper->dump_skip = xstrtoul_range_sfx(optarg, /*base:*/ 0, /*lo:*/ 0, /*hi:*/ LONG_MAX, suffixes);
+ } /* else */
+ if (ch == 'v') {
+ dumper->dump_vflag = ALL;
+ }
+#if ENABLE_FEATURE_HEXDUMP_REVERSE
+ if (ch == 'R') {
+ rdump = 1;
+ }
+#endif
+ }
+
+ if (!dumper->fshead) {
+ bb_dump_add(dumper, add_first);
+ bb_dump_add(dumper, "\"%07.7_ax \" 8/2 \"%04x \" \"\\n\"");
+ }
+
+ argv += optind;
+
+#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
+}
diff --git a/ap/app/busybox/src/util-linux/hwclock.c b/ap/app/busybox/src/util-linux/hwclock.c
new file mode 100644
index 0000000..379eeb2
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/hwclock.c
@@ -0,0 +1,328 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini hwclock implementation for busybox
+ *
+ * Copyright (C) 2002 Robert Griebl <griebl@gmx.de>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+*/
+
+#include "libbb.h"
+/* After libbb.h, since it needs sys/types.h on some systems */
+#include <sys/utsname.h>
+#include "rtc_.h"
+
+/* diff code is disabled: it's not sys/hw clock diff, it's some useless
+ * "time between hwclock was started and we saw CMOS tick" quantity.
+ * It's useless since hwclock is started at a random moment,
+ * thus the quantity is also random, useless. Showing 0.000000 does not
+ * deprive us from any useful info.
+ *
+ * SHOW_HWCLOCK_DIFF code in this file shows the difference between system
+ * and hw clock. It is useful, but not compatible with standard hwclock.
+ * Thus disabled.
+ */
+#define SHOW_HWCLOCK_DIFF 0
+
+
+#if !SHOW_HWCLOCK_DIFF
+# define read_rtc(pp_rtcname, sys_tv, utc) read_rtc(pp_rtcname, utc)
+#endif
+static time_t read_rtc(const char **pp_rtcname, struct timeval *sys_tv, int utc)
+{
+ struct tm tm_time;
+ int fd;
+
+ fd = rtc_xopen(pp_rtcname, O_RDONLY);
+
+ rtc_read_tm(&tm_time, fd);
+
+#if SHOW_HWCLOCK_DIFF
+ {
+ int before = tm_time.tm_sec;
+ while (1) {
+ rtc_read_tm(&tm_time, fd);
+ gettimeofday(sys_tv, NULL);
+ if (before != (int)tm_time.tm_sec)
+ break;
+ }
+ }
+#endif
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(fd);
+
+ return rtc_tm2time(&tm_time, utc);
+}
+
+static void show_clock(const char **pp_rtcname, int utc)
+{
+#if SHOW_HWCLOCK_DIFF
+ struct timeval sys_tv;
+#endif
+ time_t t = read_rtc(pp_rtcname, &sys_tv, utc);
+
+#if ENABLE_LOCALE_SUPPORT
+ /* Standard hwclock uses locale-specific output format */
+ char cp[64];
+ struct tm *ptm = localtime(&t);
+ strftime(cp, sizeof(cp), "%c", ptm);
+#else
+ char *cp = ctime(&t);
+ strchrnul(cp, '\n')[0] = '\0';
+#endif
+
+#if !SHOW_HWCLOCK_DIFF
+ printf("%s 0.000000 seconds\n", cp);
+#else
+ {
+ long diff = sys_tv.tv_sec - t;
+ if (diff < 0 /*&& tv.tv_usec != 0*/) {
+ /* Why we need diff++? */
+ /* diff >= 0 is ok: | diff < 0, can't just use tv.tv_usec: */
+ /* 45.520820 | 43.520820 */
+ /* - 44.000000 | - 45.000000 */
+ /* = 1.520820 | = -1.479180, not -2.520820! */
+ diff++;
+ /* Should be 1000000 - tv.tv_usec, but then we must check tv.tv_usec != 0 */
+ sys_tv.tv_usec = 999999 - sys_tv.tv_usec;
+ }
+ printf("%s %ld.%06lu seconds\n", cp, diff, (unsigned long)sys_tv.tv_usec);
+ }
+#endif
+}
+
+static void to_sys_clock(const char **pp_rtcname, int utc)
+{
+ struct timeval tv;
+ struct timezone tz;
+
+ tz.tz_minuteswest = timezone/60 - 60*daylight;
+ tz.tz_dsttime = 0;
+
+ tv.tv_sec = read_rtc(pp_rtcname, NULL, utc);
+ tv.tv_usec = 0;
+ if (settimeofday(&tv, &tz))
+ bb_perror_msg_and_die("settimeofday");
+}
+
+static void from_sys_clock(const char **pp_rtcname, int utc)
+{
+#if 1
+ struct timeval tv;
+ struct tm tm_time;
+ int rtc;
+
+ rtc = rtc_xopen(pp_rtcname, O_WRONLY);
+ gettimeofday(&tv, NULL);
+ /* Prepare tm_time */
+ if (sizeof(time_t) == sizeof(tv.tv_sec)) {
+ if (utc)
+ gmtime_r((time_t*)&tv.tv_sec, &tm_time);
+ else
+ localtime_r((time_t*)&tv.tv_sec, &tm_time);
+ } else {
+ time_t t = tv.tv_sec;
+ if (utc)
+ gmtime_r(&t, &tm_time);
+ else
+ localtime_r(&t, &tm_time);
+ }
+#else
+/* Bloated code which tries to set hw clock with better precision.
+ * On x86, even though code does set hw clock within <1ms of exact
+ * whole seconds, apparently hw clock (at least on some machines)
+ * doesn't reset internal fractional seconds to 0,
+ * making all this a pointless excercise.
+ */
+ /* If we see that we are N usec away from whole second,
+ * we'll sleep for N-ADJ usecs. ADJ corrects for the fact
+ * that CPU is not infinitely fast.
+ * On infinitely fast CPU, next wakeup would be
+ * on (exactly_next_whole_second - ADJ). On real CPUs,
+ * this difference between current time and whole second
+ * is less than ADJ (assuming system isn't heavily loaded).
+ */
+ /* Small value of 256us gives very precise sync for 2+ GHz CPUs.
+ * Slower CPUs will fail to sync and will go to bigger
+ * ADJ values. qemu-emulated armv4tl with ~100 MHz
+ * performance ends up using ADJ ~= 4*1024 and it takes
+ * 2+ secs (2 tries with successively larger ADJ)
+ * to sync. Even straced one on the same qemu (very slow)
+ * takes only 4 tries.
+ */
+#define TWEAK_USEC 256
+ unsigned adj = TWEAK_USEC;
+ struct tm tm_time;
+ struct timeval tv;
+ int rtc = rtc_xopen(pp_rtcname, O_WRONLY);
+
+ /* Try to catch the moment when whole second is close */
+ while (1) {
+ unsigned rem_usec;
+ time_t t;
+
+ gettimeofday(&tv, NULL);
+
+ t = tv.tv_sec;
+ rem_usec = 1000000 - tv.tv_usec;
+ if (rem_usec < adj) {
+ /* Close enough */
+ small_rem:
+ t++;
+ }
+
+ /* Prepare tm_time from t */
+ if (utc)
+ gmtime_r(&t, &tm_time); /* may read /etc/xxx (it takes time) */
+ else
+ localtime_r(&t, &tm_time); /* same */
+
+ if (adj >= 32*1024) {
+ break; /* 32 ms diff and still no luck?? give up trying to sync */
+ }
+
+ /* gmtime/localtime took some time, re-get cur time */
+ gettimeofday(&tv, NULL);
+
+ if (tv.tv_sec < t /* we are still in old second */
+ || (tv.tv_sec == t && tv.tv_usec < adj) /* not too far into next second */
+ ) {
+ break; /* good, we are in sync! */
+ }
+
+ rem_usec = 1000000 - tv.tv_usec;
+ if (rem_usec < adj) {
+ t = tv.tv_sec;
+ goto small_rem; /* already close to next sec, don't sleep */
+ }
+
+ /* Try to sync up by sleeping */
+ usleep(rem_usec - adj);
+
+ /* Jump to 1ms diff, then increase fast (x2): EVERY loop
+ * takes ~1 sec, people won't like slowly converging code here!
+ */
+ //bb_error_msg("adj:%d tv.tv_usec:%d", adj, (int)tv.tv_usec);
+ if (adj < 512)
+ adj = 512;
+ /* ... and if last "overshoot" does not look insanely big,
+ * just use it as adj increment. This makes convergence faster.
+ */
+ if (tv.tv_usec < adj * 8) {
+ adj += tv.tv_usec;
+ continue;
+ }
+ adj *= 2;
+ }
+ /* Debug aid to find "optimal" TWEAK_USEC with nearly exact sync.
+ * Look for a value which makes tv_usec close to 999999 or 0.
+ * For 2.20GHz Intel Core 2: optimal TWEAK_USEC ~= 200
+ */
+ //bb_error_msg("tv.tv_usec:%d", (int)tv.tv_usec);
+#endif
+
+ tm_time.tm_isdst = 0;
+ xioctl(rtc, RTC_SET_TIME, &tm_time);
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(rtc);
+}
+
+/*
+ * At system boot, kernel may set system time from RTC,
+ * but it knows nothing about timezones. If RTC is in local time,
+ * then system time is wrong - it is offset by timezone.
+ * This option corrects system time if RTC is in local time,
+ * and (always) sets in-kernel timezone.
+ *
+ * This is an alternate option to --hctosys that does not read the
+ * hardware clock.
+ */
+static void set_system_clock_timezone(int utc)
+{
+ struct timeval tv;
+ struct tm *broken;
+ struct timezone tz;
+
+ gettimeofday(&tv, NULL);
+ broken = localtime(&tv.tv_sec);
+ tz.tz_minuteswest = timezone / 60;
+ if (broken->tm_isdst)
+ tz.tz_minuteswest -= 60;
+ tz.tz_dsttime = 0;
+ gettimeofday(&tv, NULL);
+ if (!utc)
+ tv.tv_sec += tz.tz_minuteswest * 60;
+ if (settimeofday(&tv, &tz))
+ bb_perror_msg_and_die("settimeofday");
+}
+
+//usage:#define hwclock_trivial_usage
+//usage: IF_FEATURE_HWCLOCK_LONG_OPTIONS(
+//usage: "[-r|--show] [-s|--hctosys] [-w|--systohc] [-t|--systz]"
+//usage: " [-l|--localtime] [-u|--utc]"
+//usage: " [-f|--rtc FILE]"
+//usage: )
+//usage: IF_NOT_FEATURE_HWCLOCK_LONG_OPTIONS(
+//usage: "[-r] [-s] [-w] [-t] [-l] [-u] [-f FILE]"
+//usage: )
+//usage:#define hwclock_full_usage "\n\n"
+//usage: "Query and set hardware clock (RTC)\n"
+//usage: "\n -r Show hardware clock time"
+//usage: "\n -s Set system time from hardware clock"
+//usage: "\n -w Set hardware clock from system time"
+//usage: "\n -t Set in-kernel timezone, correct system time"
+//usage: "\n if hardware clock is in local time"
+//usage: "\n -u Assume hardware clock is kept in UTC"
+//usage: "\n -l Assume hardware clock is kept in local time"
+//usage: "\n -f FILE Use specified device (e.g. /dev/rtc2)"
+
+#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_SYSTZ 0x20
+#define HWCLOCK_OPT_RTCFILE 0x40
+
+int hwclock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int hwclock_main(int argc UNUSED_PARAM, char **argv)
+{
+ const char *rtcname = NULL;
+ unsigned opt;
+ int utc;
+
+#if ENABLE_FEATURE_HWCLOCK_LONG_OPTIONS
+ static const char hwclock_longopts[] ALIGN1 =
+ "localtime\0" No_argument "l" /* short opt is non-standard */
+ "utc\0" No_argument "u"
+ "show\0" No_argument "r"
+ "hctosys\0" No_argument "s"
+ "systohc\0" No_argument "w"
+ "systz\0" No_argument "t" /* short opt is non-standard */
+ "rtc\0" Required_argument "f"
+ ;
+ applet_long_options = hwclock_longopts;
+#endif
+ opt_complementary = "r--wst:w--rst:s--wrt:t--rsw:l--u:u--l";
+ opt = getopt32(argv, "lurswtf:", &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(&rtcname, utc);
+ else if (opt & HWCLOCK_OPT_SYSTOHC)
+ from_sys_clock(&rtcname, utc);
+ else if (opt & HWCLOCK_OPT_SYSTZ)
+ set_system_clock_timezone(utc);
+ else
+ /* default HWCLOCK_OPT_SHOW */
+ show_clock(&rtcname, utc);
+
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/ipcrm.c b/ap/app/busybox/src/util-linux/ipcrm.c
new file mode 100644
index 0000000..888f70e
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/ipcrm.c
@@ -0,0 +1,227 @@
+/* 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 source tree.
+ */
+
+//usage:#define ipcrm_trivial_usage
+//usage: "[-MQS key] [-mqs id]"
+//usage:#define ipcrm_full_usage "\n\n"
+//usage: "Upper-case options MQS remove an object by shmkey value.\n"
+//usage: "Lower-case options remove an object by shmid value.\n"
+//usage: "\n -mM Remove memory segment after last detach"
+//usage: "\n -qQ Remove message queue"
+//usage: "\n -sS Remove semaphore"
+
+#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, char **argv)
+{
+ unsigned long id;
+ int nb_errors = 0;
+ union semun arg;
+
+ arg.val = 0;
+
+ while (argv[0]) {
+ id = bb_strtoul(argv[0], NULL, 10);
+ if (errno || id > INT_MAX) {
+ bb_error_msg("invalid id: %s", argv[0]);
+ nb_errors++;
+ } else {
+ int ret = 0;
+ 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("can't remove id %s", argv[0]);
+ nb_errors++;
+ }
+ }
+ 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, &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/ap/app/busybox/src/util-linux/ipcs.c b/ap/app/busybox/src/util-linux/ipcs.c
new file mode 100644
index 0000000..2668caf
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/ipcs.c
@@ -0,0 +1,637 @@
+/* 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 source tree.
+ */
+
+//usage:#define ipcs_trivial_usage
+//usage: "[[-smq] -i shmid] | [[-asmq] [-tcplu]]"
+//usage:#define ipcs_full_usage "\n\n"
+//usage: " -i Show specific resource"
+//usage: "\nResource specification:"
+//usage: "\n -m Shared memory segments"
+//usage: "\n -q Message queues"
+//usage: "\n -s Semaphore arrays"
+//usage: "\n -a All (default)"
+//usage: "\nOutput format:"
+//usage: "\n -t Time"
+//usage: "\n -c Creator"
+//usage: "\n -p Pid"
+//usage: "\n -l Limits"
+//usage: "\n -u Summary"
+
+/* 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;
+ unsigned long shm_tot; /* total allocated shm */
+ unsigned long shm_rss; /* total resident shm */
+ unsigned long shm_swp; /* total swapped shm */
+ unsigned long swap_attempts;
+ unsigned long 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 NOINLINE 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 NOINLINE 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 = (unsigned short *) (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 = (unsigned short *) (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 NOINLINE 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/ap/app/busybox/src/util-linux/losetup.c b/ap/app/busybox/src/util-linux/losetup.c
new file mode 100644
index 0000000..21108d0
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/losetup.c
@@ -0,0 +1,107 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini losetup implementation for busybox
+ *
+ * Copyright (C) 2002 Matt Kraai.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+//usage:#define losetup_trivial_usage
+//usage: "[-r] [-o OFS] LOOPDEV FILE - associate loop devices\n"
+//usage: " losetup -d LOOPDEV - disassociate\n"
+//usage: " losetup [-f] - show"
+//usage:#define losetup_full_usage "\n\n"
+//usage: " -o OFS Start OFS bytes into FILE"
+//usage: "\n -r Read-only"
+//usage: "\n -f Show first free loop device"
+//usage:
+//usage:#define losetup_notes_usage
+//usage: "No arguments will display all current associations.\n"
+//usage: "One argument (losetup /dev/loop1) will display the current association\n"
+//usage: "(if any), or disassociate it (with -d). The display shows the offset\n"
+//usage: "and filename of the file the loop device is currently bound to.\n\n"
+//usage: "Two arguments (losetup /dev/loop1 file.img) create a new association,\n"
+//usage: "with an optional offset (-o 12345). Encryption is not yet supported.\n"
+//usage: "losetup -f will show the first loop free loop device\n\n"
+
+#include "libbb.h"
+
+int losetup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int losetup_main(int argc UNUSED_PARAM, char **argv)
+{
+ unsigned opt;
+ int n;
+ char *opt_o;
+ unsigned long long offset = 0;
+ enum {
+ OPT_d = (1 << 0),
+ OPT_o = (1 << 1),
+ OPT_f = (1 << 2),
+ OPT_r = (1 << 3), /* must be last */
+ };
+
+ /* max 2 args, -d,-o,-f opts are mutually exclusive */
+ opt_complementary = "?2:d--of:o--df:f--do";
+ opt = getopt32(argv, "do:fr", &opt_o);
+ argv += optind;
+
+ if (opt == OPT_o)
+ offset = xatoull(opt_o);
+
+ if (opt == OPT_d) {
+ /* -d BLOCKDEV */
+ if (!argv[0] || argv[1])
+ bb_show_usage();
+ if (del_loop(argv[0]))
+ bb_simple_perror_msg_and_die(argv[0]);
+ return EXIT_SUCCESS;
+ }
+
+ if (argv[0]) {
+ char *s;
+
+ if (opt == OPT_f) /* -f should not have arguments */
+ bb_show_usage();
+
+ if (argv[1]) {
+ /* [-r] [-o OFS] BLOCKDEV FILE */
+ if (set_loop(&argv[0], argv[1], offset, (opt / OPT_r)) < 0)
+ bb_simple_perror_msg_and_die(argv[0]);
+ return EXIT_SUCCESS;
+ }
+ /* [-r] [-o OFS] BLOCKDEV */
+ 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;
+ }
+
+ /* [-r] [-o OFS|-f] with no params */
+ n = 0;
+ while (1) {
+ char *s;
+ char dev[LOOP_NAMESIZE];
+
+ sprintf(dev, LOOP_FORMAT, n);
+ s = query_loop(dev);
+ n++;
+ if (!s) {
+ if (n > 9 && errno && errno != ENXIO)
+ return EXIT_SUCCESS;
+ if (opt == OPT_f) {
+ puts(dev);
+ return EXIT_SUCCESS;
+ }
+ } else {
+ if (opt != OPT_f)
+ printf("%s: %s\n", dev, s);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(s);
+ }
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/util-linux/lspci.c b/ap/app/busybox/src/util-linux/lspci.c
new file mode 100644
index 0000000..514678a
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/lspci.c
@@ -0,0 +1,112 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * lspci implementation for busybox
+ *
+ * Copyright (C) 2009 Malek Degachi <malek-degachi@laposte.net>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+//usage:#define lspci_trivial_usage
+//usage: "[-mk]"
+//usage:#define lspci_full_usage "\n\n"
+//usage: "List all PCI devices"
+//usage: "\n"
+//usage: "\n -m Parsable output"
+//usage: "\n -k Show driver"
+
+#include "libbb.h"
+
+enum {
+ OPT_m = (1 << 0),
+ OPT_k = (1 << 1),
+};
+
+/*
+ * PCI_SLOT_NAME PCI_CLASS: PCI_VID:PCI_DID [PCI_SUBSYS_VID:PCI_SUBSYS_DID] [DRIVER]
+ */
+static int FAST_FUNC fileAction(
+ const char *fileName,
+ struct stat *statbuf UNUSED_PARAM,
+ void *userData UNUSED_PARAM,
+ int depth UNUSED_PARAM)
+{
+ parser_t *parser;
+ char *tokens[3];
+ char *pci_slot_name = NULL, *driver = NULL;
+ int pci_class = 0, pci_vid = 0, pci_did = 0;
+ int pci_subsys_vid = 0, pci_subsys_did = 0;
+
+ char *uevent_filename = concat_path_file(fileName, "/uevent");
+ parser = config_open2(uevent_filename, fopen_for_read);
+ free(uevent_filename);
+
+ while (config_read(parser, tokens, 3, 2, "\0:=", PARSE_NORMAL)) {
+ if (strcmp(tokens[0], "DRIVER") == 0) {
+ driver = xstrdup(tokens[1]);
+ continue;
+ }
+
+ if (strcmp(tokens[0], "PCI_CLASS") == 0) {
+ pci_class = xstrtou(tokens[1], 16)>>8;
+ continue;
+ }
+
+ if (strcmp(tokens[0], "PCI_ID") == 0) {
+ pci_vid = xstrtou(tokens[1], 16);
+ pci_did = xstrtou(tokens[2], 16);
+ continue;
+ }
+
+ if (strcmp(tokens[0], "PCI_SUBSYS_ID") == 0) {
+ pci_subsys_vid = xstrtou(tokens[1], 16);
+ pci_subsys_did = xstrtou(tokens[2], 16);
+ continue;
+ }
+
+ if (strcmp(tokens[0], "PCI_SLOT_NAME") == 0) {
+ pci_slot_name = xstrdup(tokens[2]);
+ continue;
+ }
+ }
+ config_close(parser);
+
+
+ if (option_mask32 & OPT_m) {
+ printf("%s \"Class %04x\" \"%04x\" \"%04x\" \"%04x\" \"%04x\"",
+ pci_slot_name, pci_class, pci_vid, pci_did,
+ pci_subsys_vid, pci_subsys_did);
+ } else {
+ printf("%s Class %04x: %04x:%04x",
+ pci_slot_name, pci_class, pci_vid, pci_did);
+ }
+
+ if ((option_mask32 & OPT_k) && driver) {
+ if (option_mask32 & OPT_m) {
+ printf(" \"%s\"", driver);
+ } else {
+ printf(" %s", driver);
+ }
+ }
+ bb_putchar('\n');
+
+ free(driver);
+ free(pci_slot_name);
+
+ return TRUE;
+}
+
+int lspci_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int lspci_main(int argc UNUSED_PARAM, char **argv)
+{
+ getopt32(argv, "m" /*non-compat:*/ "k" /*ignored:*/ "nv");
+
+ recursive_action("/sys/bus/pci/devices",
+ ACTION_RECURSE,
+ fileAction,
+ NULL, /* dirAction */
+ NULL, /* userData */
+ 0 /* depth */);
+
+ return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/util-linux/lsusb.c b/ap/app/busybox/src/util-linux/lsusb.c
new file mode 100644
index 0000000..540f21e
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/lsusb.c
@@ -0,0 +1,75 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * lsusb implementation for busybox
+ *
+ * Copyright (C) 2009 Malek Degachi <malek-degachi@laposte.net>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+//usage:#define lsusb_trivial_usage NOUSAGE_STR
+//usage:#define lsusb_full_usage ""
+
+#include "libbb.h"
+
+static int FAST_FUNC fileAction(
+ const char *fileName,
+ struct stat *statbuf UNUSED_PARAM,
+ void *userData UNUSED_PARAM,
+ int depth UNUSED_PARAM)
+{
+ parser_t *parser;
+ char *tokens[4];
+ char *busnum = NULL, *devnum = NULL;
+ int product_vid = 0, product_did = 0;
+ char *uevent_filename = concat_path_file(fileName, "/uevent");
+
+ parser = config_open2(uevent_filename, fopen_for_read);
+ free(uevent_filename);
+
+ while (config_read(parser, tokens, 4, 2, "\\/=", PARSE_NORMAL)) {
+ if ((parser->lineno == 1) && strcmp(tokens[0], "DEVTYPE") == 0) {
+ break;
+ }
+
+ if (strcmp(tokens[0], "PRODUCT") == 0) {
+ product_vid = xstrtou(tokens[1], 16);
+ product_did = xstrtou(tokens[2], 16);
+ continue;
+ }
+
+ if (strcmp(tokens[0], "BUSNUM") == 0) {
+ busnum = xstrdup(tokens[1]);
+ continue;
+ }
+
+ if (strcmp(tokens[0], "DEVNUM") == 0) {
+ devnum = xstrdup(tokens[1]);
+ continue;
+ }
+ }
+ config_close(parser);
+
+ if (busnum) {
+ printf("Bus %s Device %s: ID %04x:%04x\n", busnum, devnum, product_vid, product_did);
+ free(busnum);
+ free(devnum);
+ }
+
+ return TRUE;
+}
+
+int lsusb_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int lsusb_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
+{
+ /* no options, no getopt */
+
+ recursive_action("/sys/bus/usb/devices",
+ ACTION_RECURSE,
+ fileAction,
+ NULL, /* dirAction */
+ NULL, /* userData */
+ 0 /* depth */);
+
+ return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/util-linux/mdev.c b/ap/app/busybox/src/util-linux/mdev.c
new file mode 100644
index 0000000..75de14f
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/mdev.c
@@ -0,0 +1,955 @@
+/* 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 GPLv2, see file LICENSE in this source tree.
+ */
+
+//config:config MDEV
+//config: bool "mdev"
+//config: default y
+//config: select PLATFORM_LINUX
+//config: help
+//config: mdev is a mini-udev implementation for dynamically creating device
+//config: nodes in the /dev directory.
+//config:
+//config: For more information, please see docs/mdev.txt
+//config:
+//config:config FEATURE_MDEV_CONF
+//config: bool "Support /etc/mdev.conf"
+//config: default y
+//config: depends on MDEV
+//config: help
+//config: Add support for the mdev config file to control ownership and
+//config: permissions of the device nodes.
+//config:
+//config: For more information, please see docs/mdev.txt
+//config:
+//config:config FEATURE_MDEV_RENAME
+//config: bool "Support subdirs/symlinks"
+//config: default y
+//config: depends on FEATURE_MDEV_CONF
+//config: help
+//config: Add support for renaming devices and creating symlinks.
+//config:
+//config: For more information, please see docs/mdev.txt
+//config:
+//config:config FEATURE_MDEV_RENAME_REGEXP
+//config: bool "Support regular expressions substitutions when renaming device"
+//config: default y
+//config: depends on FEATURE_MDEV_RENAME
+//config: help
+//config: Add support for regular expressions substitutions when renaming
+//config: device.
+//config:
+//config:config FEATURE_MDEV_EXEC
+//config: bool "Support command execution at device addition/removal"
+//config: default y
+//config: depends on FEATURE_MDEV_CONF
+//config: help
+//config: This adds support for an optional field to /etc/mdev.conf for
+//config: executing commands when devices are created/removed.
+//config:
+//config: For more information, please see docs/mdev.txt
+//config:
+//config:config FEATURE_MDEV_LOAD_FIRMWARE
+//config: bool "Support loading of firmwares"
+//config: default y
+//config: depends on MDEV
+//config: help
+//config: Some devices need to load firmware before they can be usable.
+//config:
+//config: These devices will request userspace look up the files in
+//config: /lib/firmware/ and if it exists, send it to the kernel for
+//config: loading into the hardware.
+
+//applet:IF_MDEV(APPLET(mdev, BB_DIR_SBIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_MDEV) += mdev.o
+
+//usage:#define mdev_trivial_usage
+//usage: "[-s]"
+//usage:#define mdev_full_usage "\n\n"
+//usage: "mdev -s is to be run during boot to scan /sys and populate /dev.\n"
+//usage: "\n"
+//usage: "Bare mdev is a kernel hotplug helper. To activate it:\n"
+//usage: " echo /sbin/mdev >/proc/sys/kernel/hotplug\n"
+//usage: IF_FEATURE_MDEV_CONF(
+//usage: "\n"
+//usage: "It uses /etc/mdev.conf with lines\n"
+//usage: " [-]DEVNAME UID:GID PERM"
+//usage: IF_FEATURE_MDEV_RENAME(" [>|=PATH]|[!]")
+//usage: IF_FEATURE_MDEV_EXEC(" [@|$|*PROG]")
+//usage: "\n"
+//usage: "where DEVNAME is device name regex, @major,minor[-minor2], or\n"
+//usage: "environment variable regex. A common use of the latter is\n"
+//usage: "to load modules for hotplugged devices:\n"
+//usage: " $MODALIAS=.* 0:0 660 @modprobe \"$MODALIAS\"\n"
+//usage: )
+//usage: "\n"
+//usage: "If /dev/mdev.seq file exists, mdev will wait for its value\n"
+//usage: "to match $SEQNUM variable. This prevents plug/unplug races.\n"
+//usage: "To activate this feature, create empty /dev/mdev.seq at boot.\n"
+//usage: "\n"
+//usage: "If /dev/mdev.log file exists, debug log will be appended to it."
+
+#include "libbb.h"
+#include "xregex.h"
+
+/* "mdev -s" scans /sys/class/xxx, looking for directories which have dev
+ * file (it is of the form "M:m\n"). Example: /sys/class/tty/tty0/dev
+ * contains "4:0\n". Directory name is taken as device name, path component
+ * directly after /sys/class/ as subsystem. In this example, "tty0" and "tty".
+ * Then mdev creates the /dev/device_name node.
+ * If /sys/class/.../dev file does not exist, mdev still may act
+ * on this device: see "@|$|*command args..." parameter in config file.
+ *
+ * mdev w/o parameters is called as hotplug helper. It takes device
+ * and subsystem names from $DEVPATH and $SUBSYSTEM, extracts
+ * maj,min from "/sys/$DEVPATH/dev" and also examines
+ * $ACTION ("add"/"delete") and $FIRMWARE.
+ *
+ * If action is "add", mdev creates /dev/device_name similarly to mdev -s.
+ * (todo: explain "delete" and $FIRMWARE)
+ *
+ * If /etc/mdev.conf exists, it may modify /dev/device_name's properties.
+ *
+ * Leading minus in 1st field means "don't stop on this line", otherwise
+ * search is stopped after the matching line is encountered.
+ *
+ * $envvar=regex format is useful for loading modules for hot-plugged devices
+ * which do not have driver loaded yet. In this case /sys/class/.../dev
+ * does not exist, but $MODALIAS is set to needed module's name
+ * (actually, an alias to it) by kernel. This rule instructs mdev
+ * to load the module and exit:
+ * $MODALIAS=.* 0:0 660 @modprobe "$MODALIAS"
+ * The kernel will generate another hotplug event when /sys/class/.../dev
+ * file appears.
+ *
+ * When line matches, the device node is created, chmod'ed and chown'ed,
+ * moved to path, and if >path, a symlink to moved node is created,
+ * all this if /sys/class/.../dev exists.
+ * Examples:
+ * =loop/ - moves to /dev/loop
+ * >disk/sda%1 - moves to /dev/disk/sdaN, makes /dev/sdaN a symlink
+ *
+ * Then "command args..." is executed (via sh -c 'command args...').
+ * @:execute on creation, $:on deletion, *:on both.
+ * This happens regardless of /sys/class/.../dev existence.
+ */
+
+/* Kernel's hotplug environment constantly changes.
+ * Here are new cases I observed on 3.1.0:
+ *
+ * Case with $DEVNAME and $DEVICE, not just $DEVPATH:
+ * ACTION=add
+ * BUSNUM=001
+ * DEVICE=/proc/bus/usb/001/003
+ * DEVNAME=bus/usb/001/003
+ * DEVNUM=003
+ * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5
+ * DEVTYPE=usb_device
+ * MAJOR=189
+ * MINOR=2
+ * PRODUCT=18d1/4e12/227
+ * SUBSYSTEM=usb
+ * TYPE=0/0/0
+ *
+ * Case with $DEVICE, but no $DEVNAME - apparenty, usb iface notification?
+ * "Please load me a module" thing?
+ * ACTION=add
+ * DEVICE=/proc/bus/usb/001/003
+ * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0
+ * DEVTYPE=usb_interface
+ * INTERFACE=8/6/80
+ * MODALIAS=usb:v18D1p4E12d0227dc00dsc00dp00ic08isc06ip50
+ * PRODUCT=18d1/4e12/227
+ * SUBSYSTEM=usb
+ * TYPE=0/0/0
+ *
+ * ACTION=add
+ * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5
+ * DEVTYPE=scsi_host
+ * SUBSYSTEM=scsi
+ *
+ * ACTION=add
+ * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/scsi_host/host5
+ * SUBSYSTEM=scsi_host
+ *
+ * ACTION=add
+ * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0
+ * DEVTYPE=scsi_target
+ * SUBSYSTEM=scsi
+ *
+ * Case with strange $MODALIAS:
+ * ACTION=add
+ * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0
+ * DEVTYPE=scsi_device
+ * MODALIAS=scsi:t-0x00
+ * SUBSYSTEM=scsi
+ *
+ * ACTION=add
+ * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0/scsi_disk/5:0:0:0
+ * SUBSYSTEM=scsi_disk
+ *
+ * ACTION=add
+ * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0/scsi_device/5:0:0:0
+ * SUBSYSTEM=scsi_device
+ *
+ * Case with explicit $MAJOR/$MINOR (no need to read /sys/$DEVPATH/dev?):
+ * ACTION=add
+ * DEVNAME=bsg/5:0:0:0
+ * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0/bsg/5:0:0:0
+ * MAJOR=253
+ * MINOR=1
+ * SUBSYSTEM=bsg
+ *
+ * ACTION=add
+ * DEVPATH=/devices/virtual/bdi/8:16
+ * SUBSYSTEM=bdi
+ *
+ * ACTION=add
+ * DEVNAME=sdb
+ * DEVPATH=/block/sdb
+ * DEVTYPE=disk
+ * MAJOR=8
+ * MINOR=16
+ * SUBSYSTEM=block
+ *
+ * Case with ACTION=change:
+ * ACTION=change
+ * DEVNAME=sdb
+ * DEVPATH=/block/sdb
+ * DEVTYPE=disk
+ * DISK_MEDIA_CHANGE=1
+ * MAJOR=8
+ * MINOR=16
+ * SUBSYSTEM=block
+ */
+
+static const char keywords[] ALIGN1 = "add\0remove\0change\0";
+enum { OP_add, OP_remove };
+
+struct rule {
+ bool keep_matching;
+ bool regex_compiled;
+ mode_t mode;
+ int maj, min0, min1;
+ struct bb_uidgid_t ugid;
+ char *envvar;
+ char *ren_mov;
+ IF_FEATURE_MDEV_EXEC(char *r_cmd;)
+ regex_t match;
+};
+
+struct globals {
+ int root_major, root_minor;
+ smallint verbose;
+ char *subsystem;
+#if ENABLE_FEATURE_MDEV_CONF
+ const char *filename;
+ parser_t *parser;
+ struct rule **rule_vec;
+ unsigned rule_idx;
+#endif
+ struct rule cur_rule;
+} FIX_ALIASING;
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define INIT_G() do { \
+ IF_NOT_FEATURE_MDEV_CONF(G.cur_rule.maj = -1;) \
+ IF_NOT_FEATURE_MDEV_CONF(G.cur_rule.mode = 0660;) \
+} while (0)
+
+
+/* Prevent infinite loops in /sys symlinks */
+#define MAX_SYSFS_DEPTH 3
+
+/* We use additional 64+ bytes in make_device() */
+#define SCRATCH_SIZE 80
+
+#if 0
+# define dbg(...) bb_error_msg(__VA_ARGS__)
+#else
+# define dbg(...) ((void)0)
+#endif
+
+
+#if ENABLE_FEATURE_MDEV_CONF
+
+static void make_default_cur_rule(void)
+{
+ memset(&G.cur_rule, 0, sizeof(G.cur_rule));
+ G.cur_rule.maj = -1; /* "not a @major,minor rule" */
+ G.cur_rule.mode = 0660;
+}
+
+static void clean_up_cur_rule(void)
+{
+ free(G.cur_rule.envvar);
+ if (G.cur_rule.regex_compiled)
+ regfree(&G.cur_rule.match);
+ free(G.cur_rule.ren_mov);
+ IF_FEATURE_MDEV_EXEC(free(G.cur_rule.r_cmd);)
+ make_default_cur_rule();
+}
+
+static void parse_next_rule(void)
+{
+ /* Note: on entry, G.cur_rule is set to default */
+ while (1) {
+ char *tokens[4];
+ char *val;
+
+ /* No PARSE_EOL_COMMENTS, because command may contain '#' chars */
+ if (!config_read(G.parser, tokens, 4, 3, "# \t", PARSE_NORMAL & ~PARSE_EOL_COMMENTS))
+ break;
+
+ /* Fields: [-]regex uid:gid mode [alias] [cmd] */
+ dbg("token1:'%s'", tokens[1]);
+
+ /* 1st field */
+ val = tokens[0];
+ G.cur_rule.keep_matching = ('-' == val[0]);
+ val += G.cur_rule.keep_matching; /* swallow leading dash */
+ if (val[0] == '@') {
+ /* @major,minor[-minor2] */
+ /* (useful when name is ambiguous:
+ * "/sys/class/usb/lp0" and
+ * "/sys/class/printer/lp0")
+ */
+ int sc = sscanf(val, "@%u,%u-%u", &G.cur_rule.maj, &G.cur_rule.min0, &G.cur_rule.min1);
+ if (sc < 2 || G.cur_rule.maj < 0) {
+ bb_error_msg("bad @maj,min on line %d", G.parser->lineno);
+ goto next_rule;
+ }
+ if (sc == 2)
+ G.cur_rule.min1 = G.cur_rule.min0;
+ } else {
+ if (val[0] == '$') {
+ char *eq = strchr(++val, '=');
+ if (!eq) {
+ bb_error_msg("bad $envvar=regex on line %d", G.parser->lineno);
+ goto next_rule;
+ }
+ G.cur_rule.envvar = xstrndup(val, eq - val);
+ val = eq + 1;
+ }
+ xregcomp(&G.cur_rule.match, val, REG_EXTENDED);
+ G.cur_rule.regex_compiled = 1;
+ }
+
+ /* 2nd field: uid:gid - device ownership */
+ if (get_uidgid(&G.cur_rule.ugid, tokens[1], /*allow_numeric:*/ 1) == 0) {
+ bb_error_msg("unknown user/group '%s' on line %d", tokens[1], G.parser->lineno);
+ goto next_rule;
+ }
+
+ /* 3rd field: mode - device permissions */
+ bb_parse_mode(tokens[2], &G.cur_rule.mode);
+
+ /* 4th field (opt): ">|=alias" or "!" to not create the node */
+ val = tokens[3];
+ if (ENABLE_FEATURE_MDEV_RENAME && val && strchr(">=!", val[0])) {
+ char *s = skip_non_whitespace(val);
+ G.cur_rule.ren_mov = xstrndup(val, s - val);
+ val = skip_whitespace(s);
+ }
+
+ if (ENABLE_FEATURE_MDEV_EXEC && val && val[0]) {
+ const char *s = "$@*";
+ const char *s2 = strchr(s, val[0]);
+ if (!s2) {
+ bb_error_msg("bad line %u", G.parser->lineno);
+ goto next_rule;
+ }
+ IF_FEATURE_MDEV_EXEC(G.cur_rule.r_cmd = xstrdup(val);)
+ }
+
+ return;
+ next_rule:
+ clean_up_cur_rule();
+ } /* while (config_read) */
+
+ dbg("config_close(G.parser)");
+ config_close(G.parser);
+ G.parser = NULL;
+
+ return;
+}
+
+/* If mdev -s, we remember rules in G.rule_vec[].
+ * Otherwise, there is no point in doing it, and we just
+ * save only one parsed rule in G.cur_rule.
+ */
+static const struct rule *next_rule(void)
+{
+ struct rule *rule;
+
+ /* Open conf file if we didn't do it yet */
+ if (!G.parser && G.filename) {
+ dbg("config_open('%s')", G.filename);
+ G.parser = config_open2(G.filename, fopen_for_read);
+ G.filename = NULL;
+ }
+
+ if (G.rule_vec) {
+ /* mdev -s */
+ /* Do we have rule parsed already? */
+ if (G.rule_vec[G.rule_idx]) {
+ dbg("< G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]);
+ return G.rule_vec[G.rule_idx++];
+ }
+ make_default_cur_rule();
+ } else {
+ /* not mdev -s */
+ clean_up_cur_rule();
+ }
+
+ /* Parse one more rule if file isn't fully read */
+ rule = &G.cur_rule;
+ if (G.parser) {
+ parse_next_rule();
+ if (G.rule_vec) { /* mdev -s */
+ rule = memcpy(xmalloc(sizeof(G.cur_rule)), &G.cur_rule, sizeof(G.cur_rule));
+ G.rule_vec = xrealloc_vector(G.rule_vec, 4, G.rule_idx);
+ G.rule_vec[G.rule_idx++] = rule;
+ dbg("> G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]);
+ }
+ }
+
+ return rule;
+}
+
+#else
+
+# define next_rule() (&G.cur_rule)
+
+#endif
+
+static void mkdir_recursive(char *name)
+{
+ /* if name has many levels ("dir1/dir2"),
+ * bb_make_directory() will create dir1 according to umask,
+ * not according to its "mode" parameter.
+ * Since we run with umask=0, need to temporarily switch it.
+ */
+ umask(022); /* "dir1" (if any) will be 0755 too */
+ bb_make_directory(name, 0755, FILEUTILS_RECUR);
+ umask(0);
+}
+
+/* Builds an alias path.
+ * This function potentionally reallocates the alias parameter.
+ * Only used for ENABLE_FEATURE_MDEV_RENAME
+ */
+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 */
+ mkdir_recursive(alias);
+ *dest = '/';
+ if (dest[1] == '\0') { /* ">bar/" => ">bar/device_name" */
+ dest = alias;
+ alias = concat_path_file(alias, device_name);
+ free(dest);
+ }
+ }
+
+ return alias;
+}
+
+/* mknod in /dev based on a path like "/sys/block/hda/hda1"
+ * NB1: path parameter needs to have SCRATCH_SIZE scratch bytes
+ * after NUL, but we promise to not mangle (IOW: to restore if needed)
+ * path string.
+ * NB2: "mdev -s" may call us many times, do not leak memory/fds!
+ *
+ * device_name = $DEVNAME (may be NULL)
+ * path = /sys/$DEVPATH
+ */
+static void make_device(char *device_name, char *path, int operation)
+{
+ int major, minor, type, len;
+
+ if (G.verbose)
+ bb_error_msg("device: %s, %s", device_name, path);
+
+ /* 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 (operation == OP_add) {
+ char *dev_maj_min = path + strlen(path);
+
+ 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, but we can still run scripts
+ * based on device name */
+ } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) == 2) {
+ if (G.verbose)
+ bb_error_msg("maj,min: %u,%u", major, minor);
+ } else {
+ major = -1;
+ }
+ }
+ /* else: for delete, -1 still deletes the node, but < -1 suppresses that */
+
+ /* Determine device name, type, major and minor */
+ if (!device_name)
+ device_name = (char*) 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/") || (G.subsystem && strncmp(G.subsystem, "block", 5) == 0))
+ type = S_IFBLK;
+
+#if ENABLE_FEATURE_MDEV_CONF
+ G.rule_idx = 0; /* restart from the beginning (think mdev -s) */
+#endif
+ for (;;) {
+ const char *str_to_match;
+ regmatch_t off[1 + 9 * ENABLE_FEATURE_MDEV_RENAME_REGEXP];
+ char *command;
+ char *alias;
+ char aliaslink = aliaslink; /* for compiler */
+ char *node_name;
+ const struct rule *rule;
+
+ str_to_match = device_name;
+
+ rule = next_rule();
+
+#if ENABLE_FEATURE_MDEV_CONF
+ if (rule->maj >= 0) { /* @maj,min rule */
+ if (major != rule->maj)
+ continue;
+ if (minor < rule->min0 || minor > rule->min1)
+ continue;
+ memset(off, 0, sizeof(off));
+ goto rule_matches;
+ }
+ if (rule->envvar) { /* $envvar=regex rule */
+ str_to_match = getenv(rule->envvar);
+ dbg("getenv('%s'):'%s'", rule->envvar, str_to_match);
+ if (!str_to_match)
+ continue;
+ }
+ /* else: str_to_match = device_name */
+
+ if (rule->regex_compiled) {
+ int regex_match = regexec(&rule->match, str_to_match, ARRAY_SIZE(off), off, 0);
+ dbg("regex_match for '%s':%d", str_to_match, regex_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 (regex_match != 0
+ /* regexec returns whole pattern as "range" 0 */
+ || off[0].rm_so != 0
+ || (int)off[0].rm_eo != (int)strlen(str_to_match)
+ ) {
+ continue; /* this rule doesn't match */
+ }
+ }
+ /* else: it's final implicit "match-all" rule */
+ rule_matches:
+#endif
+ dbg("rule matched");
+
+ /* Build alias name */
+ alias = NULL;
+ if (ENABLE_FEATURE_MDEV_RENAME && rule->ren_mov) {
+ aliaslink = rule->ren_mov[0];
+ if (aliaslink == '!') {
+ /* "!": suppress node creation/deletion */
+ major = -2;
+ }
+ else if (aliaslink == '>' || aliaslink == '=') {
+ if (ENABLE_FEATURE_MDEV_RENAME_REGEXP) {
+ char *s;
+ char *p;
+ unsigned n;
+
+ /* substitute %1..9 with off[1..9], if any */
+ n = 0;
+ s = rule->ren_mov;
+ while (*s)
+ if (*s++ == '%')
+ n++;
+
+ p = alias = xzalloc(strlen(rule->ren_mov) + n * strlen(str_to_match));
+ s = rule->ren_mov + 1;
+ while (*s) {
+ *p = *s;
+ if ('%' == *s) {
+ unsigned i = (s[1] - '0');
+ if (i <= 9 && off[i].rm_so >= 0) {
+ n = off[i].rm_eo - off[i].rm_so;
+ strncpy(p, str_to_match + off[i].rm_so, n);
+ p += n - 1;
+ s++;
+ }
+ }
+ p++;
+ s++;
+ }
+ } else {
+ alias = xstrdup(rule->ren_mov + 1);
+ }
+ }
+ }
+ dbg("alias:'%s'", alias);
+
+ command = NULL;
+ IF_FEATURE_MDEV_EXEC(command = rule->r_cmd;)
+ if (command) {
+ const char *s = "$@*";
+ const char *s2 = strchr(s, command[0]);
+
+ /* Are we running this command now?
+ * Run $cmd on delete, @cmd on create, *cmd on both
+ */
+ if (s2 - s != (operation == OP_remove) || *s2 == '*') {
+ /* We are here if: '*',
+ * or: '@' and delete = 0,
+ * or: '$' and delete = 1
+ */
+ command++;
+ } else {
+ command = NULL;
+ }
+ }
+ dbg("command:'%s'", command);
+
+ /* "Execute" the line we found */
+ node_name = device_name;
+ if (ENABLE_FEATURE_MDEV_RENAME && alias) {
+ node_name = alias = build_alias(alias, device_name);
+ dbg("alias2:'%s'", alias);
+ }
+
+ if (operation == OP_add && major >= 0) {
+ char *slash = strrchr(node_name, '/');
+ if (slash) {
+ *slash = '\0';
+ mkdir_recursive(node_name);
+ *slash = '/';
+ }
+ if (G.verbose)
+ bb_error_msg("mknod: %s (%d,%d) %o", node_name, major, minor, rule->mode | type);
+ if (mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST)
+ bb_perror_msg("can't create '%s'", node_name);
+ if (ENABLE_FEATURE_MDEV_CONF) {
+ chmod(node_name, rule->mode);
+ chown(node_name, rule->ugid.uid, rule->ugid.gid);
+ }
+ if (major == G.root_major && minor == G.root_minor)
+ symlink(node_name, "root");
+ if (ENABLE_FEATURE_MDEV_RENAME && alias) {
+ if (aliaslink == '>') {
+//TODO: on devtmpfs, device_name already exists and symlink() fails.
+//End result is that instead of symlink, we have two nodes.
+//What should be done?
+ if (G.verbose)
+ bb_error_msg("symlink: %s", device_name);
+ symlink(node_name, device_name);
+ }
+ }
+ }
+
+ if (ENABLE_FEATURE_MDEV_EXEC && command) {
+ /* setenv will leak memory, use putenv/unsetenv/free */
+ char *s = xasprintf("%s=%s", "MDEV", node_name);
+ char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem);
+ putenv(s);
+ putenv(s1);
+ if (G.verbose)
+ bb_error_msg("running: %s", command);
+ if (system(command) == -1)
+ bb_perror_msg("can't run '%s'", command);
+ bb_unsetenv_and_free(s1);
+ bb_unsetenv_and_free(s);
+ }
+
+ if (operation == OP_remove && major >= -1) {
+ if (ENABLE_FEATURE_MDEV_RENAME && alias) {
+ if (aliaslink == '>') {
+ if (G.verbose)
+ bb_error_msg("unlink: %s", device_name);
+ unlink(device_name);
+ }
+ }
+ if (G.verbose)
+ bb_error_msg("unlink: %s", node_name);
+ unlink(node_name);
+ }
+
+ if (ENABLE_FEATURE_MDEV_RENAME)
+ free(alias);
+
+ /* We found matching line.
+ * Stop unless it was prefixed with '-'
+ */
+ if (!ENABLE_FEATURE_MDEV_CONF || !rule->keep_matching)
+ break;
+ } /* for (;;) */
+}
+
+/* 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(/*DEVNAME:*/ NULL, scratch, OP_add);
+
+ 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(G.subsystem);
+ G.subsystem = strrchr(fileName, '/');
+ if (G.subsystem)
+ G.subsystem = xstrdup(G.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 *firmware, const char *sysfs_path)
+{
+ int cnt;
+ int firmware_fd, loading_fd;
+
+ /* check for /lib/firmware/$FIRMWARE */
+ xchdir("/lib/firmware");
+ firmware_fd = open(firmware, O_RDONLY); /* can fail */
+
+ /* 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 >= 0)
+ goto loading;
+ sleep(1);
+ }
+ goto out;
+
+ loading:
+ cnt = 0;
+ if (firmware_fd >= 0) {
+ int data_fd;
+
+ /* 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 < 0)
+ goto out;
+ cnt = bb_copyfd_eof(firmware_fd, data_fd);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(data_fd);
+ }
+
+ /* Tell kernel result by "echo [0|-1] > /sys/$DEVPATH/loading"
+ * Note: we emit -1 also if firmware file wasn't found.
+ * There are cases when otherwise kernel would wait for minutes
+ * before timing out.
+ */
+ 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);
+ }
+}
+
+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);
+
+ INIT_G();
+
+#if ENABLE_FEATURE_MDEV_CONF
+ G.filename = "/etc/mdev.conf";
+#endif
+
+ /* We can be called as hotplug helper */
+ /* Kernel cannot provide suitable stdio fds for us, do it ourself */
+ bb_sanitize_stdio();
+
+ /* Force the configuration file settings exactly */
+ umask(0);
+
+ xchdir("/dev");
+
+ if (argv[1] && strcmp(argv[1], "-s") == 0) {
+ /* Scan:
+ * mdev -s
+ */
+ struct stat st;
+
+#if ENABLE_FEATURE_MDEV_CONF
+ /* Same as xrealloc_vector(NULL, 4, 0): */
+ G.rule_vec = xzalloc((1 << 4) * sizeof(*G.rule_vec));
+#endif
+ xstat("/", &st);
+ G.root_major = major(st.st_dev);
+ G.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_devname;
+ char *env_devpath;
+ smalluint op;
+
+ /* 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");
+ op = index_in_strings(keywords, action);
+ env_devname = getenv("DEVNAME"); /* can be NULL */
+ env_devpath = getenv("DEVPATH");
+ G.subsystem = getenv("SUBSYSTEM");
+ if (!action || !env_devpath /*|| !G.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);
+ }
+
+ {
+ int logfd = open("/dev/mdev.log", O_WRONLY | O_APPEND);
+ if (logfd >= 0) {
+ xmove_fd(logfd, STDERR_FILENO);
+ G.verbose = 1;
+ bb_error_msg("seq: %s action: %s", seq, action);
+ }
+ }
+
+ snprintf(temp, PATH_MAX, "/sys%s", env_devpath);
+ if (op == OP_remove) {
+ /* Ignoring "remove firmware". It was reported
+ * to happen and to cause erroneous deletion
+ * of device nodes. */
+ if (!fw)
+ make_device(env_devname, temp, op);
+ }
+ else if (op == OP_add) {
+ make_device(env_devname, temp, op);
+ 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/ap/app/busybox/src/util-linux/minix.h b/ap/app/busybox/src/util-linux/minix.h
new file mode 100644
index 0000000..e0fbcf7
--- /dev/null
+++ b/ap/app/busybox/src/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[];
+};
+
+/* 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/ap/app/busybox/src/util-linux/mkfs_ext2.c b/ap/app/busybox/src/util-linux/mkfs_ext2.c
new file mode 100644
index 0000000..3258d7e
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/mkfs_ext2.c
@@ -0,0 +1,696 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mkfs_ext2: utility to create EXT2 filesystem
+ * inspired by genext2fs
+ *
+ * Busybox'ed (2009) by Vladimir Dronnikov <dronnikov@gmail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//usage:#define mkfs_ext2_trivial_usage
+//usage: "[-Fn] "
+/* //usage: "[-c|-l filename] " */
+//usage: "[-b BLK_SIZE] "
+/* //usage: "[-f fragment-size] [-g blocks-per-group] " */
+//usage: "[-i INODE_RATIO] [-I INODE_SIZE] "
+/* //usage: "[-j] [-J journal-options] [-N number-of-inodes] " */
+//usage: "[-m RESERVED_PERCENT] "
+/* //usage: "[-o creator-os] [-O feature[,...]] [-q] " */
+/* //usage: "[r fs-revision-level] [-E extended-options] [-v] [-F] " */
+//usage: "[-L LABEL] "
+/* //usage: "[-M last-mounted-directory] [-S] [-T filesystem-type] " */
+//usage: "BLOCKDEV [KBYTES]"
+//usage:#define mkfs_ext2_full_usage "\n\n"
+//usage: " -b BLK_SIZE Block size, bytes"
+/* //usage: "\n -c Check device for bad blocks" */
+/* //usage: "\n -E opts Set extended options" */
+/* //usage: "\n -f size Fragment size in bytes" */
+//usage: "\n -F Force"
+/* //usage: "\n -g N Number of blocks in a block group" */
+//usage: "\n -i RATIO Max number of files is filesystem_size / RATIO"
+//usage: "\n -I BYTES Inode size (min 128)"
+/* //usage: "\n -j Create a journal (ext3)" */
+/* //usage: "\n -J opts Set journal options (size/device)" */
+/* //usage: "\n -l file Read bad blocks list from file" */
+//usage: "\n -L LBL Volume label"
+//usage: "\n -m PERCENT Percent of blocks to reserve for admin"
+/* //usage: "\n -M dir Set last mounted directory" */
+//usage: "\n -n Dry run"
+/* //usage: "\n -N N Number of inodes to create" */
+/* //usage: "\n -o os Set the 'creator os' field" */
+/* //usage: "\n -O features Dir_index/filetype/has_journal/journal_dev/sparse_super" */
+/* //usage: "\n -q Quiet" */
+/* //usage: "\n -r rev Set filesystem revision" */
+/* //usage: "\n -S Write superblock and group descriptors only" */
+/* //usage: "\n -T fs-type Set usage type (news/largefile/largefile4)" */
+/* //usage: "\n -v Verbose" */
+
+#include "libbb.h"
+#include <linux/fs.h>
+#include "bb_e2fs_defs.h"
+
+#define ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT 0
+#define ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX 1
+
+#define EXT2_HASH_HALF_MD4 1
+#define EXT2_FLAGS_SIGNED_HASH 0x0001
+#define EXT2_FLAGS_UNSIGNED_HASH 0x0002
+
+// storage helpers
+char BUG_wrong_field_size(void);
+#define STORE_LE(field, value) \
+do { \
+ if (sizeof(field) == 4) \
+ field = SWAP_LE32(value); \
+ else if (sizeof(field) == 2) \
+ field = SWAP_LE16(value); \
+ else if (sizeof(field) == 1) \
+ field = (value); \
+ else \
+ BUG_wrong_field_size(); \
+} while (0)
+
+#define FETCH_LE32(field) \
+ (sizeof(field) == 4 ? SWAP_LE32(field) : BUG_wrong_field_size())
+
+// All fields are little-endian
+struct ext2_dir {
+ uint32_t inode1;
+ uint16_t rec_len1;
+ uint8_t name_len1;
+ uint8_t file_type1;
+ char name1[4];
+ uint32_t inode2;
+ uint16_t rec_len2;
+ uint8_t name_len2;
+ uint8_t file_type2;
+ char name2[4];
+ uint32_t inode3;
+ uint16_t rec_len3;
+ uint8_t name_len3;
+ uint8_t file_type3;
+ char name3[12];
+};
+
+static unsigned int_log2(unsigned arg)
+{
+ unsigned r = 0;
+ while ((arg >>= 1) != 0)
+ r++;
+ return r;
+}
+
+// taken from mkfs_minix.c. libbb candidate?
+// "uint32_t size", since we never use it for anything >32 bits
+static uint32_t div_roundup(uint32_t size, uint32_t n)
+{
+ // Overflow-resistant
+ uint32_t res = size / n;
+ if (res * n != size)
+ res++;
+ return res;
+}
+
+static void allocate(uint8_t *bitmap, uint32_t blocksize, uint32_t start, uint32_t end)
+{
+ uint32_t i;
+
+//bb_info_msg("ALLOC: [%u][%u][%u]: [%u-%u]:=[%x],[%x]", blocksize, start, end, start/8, blocksize - end/8 - 1, (1 << (start & 7)) - 1, (uint8_t)(0xFF00 >> (end & 7)));
+ memset(bitmap, 0, blocksize);
+ i = start / 8;
+ memset(bitmap, 0xFF, i);
+ bitmap[i] = (1 << (start & 7)) - 1; //0..7 => 00000000..01111111
+ i = end / 8;
+ bitmap[blocksize - i - 1] |= 0x7F00 >> (end & 7); //0..7 => 00000000..11111110
+ memset(bitmap + blocksize - i, 0xFF, i); // N.B. no overflow here!
+}
+
+static uint32_t has_super(uint32_t x)
+{
+ // 0, 1 and powers of 3, 5, 7 up to 2^32 limit
+ static const uint32_t supers[] = {
+ 0, 1, 3, 5, 7, 9, 25, 27, 49, 81, 125, 243, 343, 625, 729,
+ 2187, 2401, 3125, 6561, 15625, 16807, 19683, 59049, 78125,
+ 117649, 177147, 390625, 531441, 823543, 1594323, 1953125,
+ 4782969, 5764801, 9765625, 14348907, 40353607, 43046721,
+ 48828125, 129140163, 244140625, 282475249, 387420489,
+ 1162261467, 1220703125, 1977326743, 3486784401/* >2^31 */,
+ };
+ const uint32_t *sp = supers + ARRAY_SIZE(supers);
+ while (1) {
+ sp--;
+ if (x == *sp)
+ return 1;
+ if (x > *sp)
+ return 0;
+ }
+}
+
+#define fd 3 /* predefined output descriptor */
+
+static void PUT(uint64_t off, void *buf, uint32_t size)
+{
+// bb_info_msg("PUT[%llu]:[%u]", off, size);
+ xlseek(fd, off, SEEK_SET);
+ xwrite(fd, buf, size);
+}
+
+// 128 and 256-byte inodes:
+// 128-byte inode is described by struct ext2_inode.
+// 256-byte one just has these fields appended:
+// __u16 i_extra_isize;
+// __u16 i_pad1;
+// __u32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */
+// __u32 i_mtime_extra; /* extra Modification time (nsec << 2 | epoch) */
+// __u32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */
+// __u32 i_crtime; /* File creation time */
+// __u32 i_crtime_extra; /* extra File creation time (nsec << 2 | epoch)*/
+// __u32 i_version_hi; /* high 32 bits for 64-bit version */
+// the rest is padding.
+//
+// linux/ext2_fs.h has "#define i_size_high i_dir_acl" which suggests that even
+// 128-byte inode is capable of describing large files (i_dir_acl is meaningful
+// only for directories, which never need i_size_high).
+//
+// Standard mke2fs creates a filesystem with 256-byte inodes if it is
+// bigger than 0.5GB.
+
+// Standard mke2fs 1.41.9:
+// Usage: mke2fs [-c|-l filename] [-b block-size] [-f fragment-size]
+// [-i bytes-per-inode] [-I inode-size] [-J journal-options]
+// [-G meta group size] [-N number-of-inodes]
+// [-m reserved-blocks-percentage] [-o creator-os]
+// [-g blocks-per-group] [-L volume-label] [-M last-mounted-directory]
+// [-O feature[,...]] [-r fs-revision] [-E extended-option[,...]]
+// [-T fs-type] [-U UUID] [-jnqvFSV] device [blocks-count]
+//
+// Options not commented below are taken but silently ignored:
+enum {
+ OPT_c = 1 << 0,
+ OPT_l = 1 << 1,
+ OPT_b = 1 << 2, // block size, in bytes
+ OPT_f = 1 << 3,
+ OPT_i = 1 << 4, // bytes per inode
+ OPT_I = 1 << 5, // custom inode size, in bytes
+ OPT_J = 1 << 6,
+ OPT_G = 1 << 7,
+ OPT_N = 1 << 8,
+ OPT_m = 1 << 9, // percentage of blocks reserved for superuser
+ OPT_o = 1 << 10,
+ OPT_g = 1 << 11,
+ OPT_L = 1 << 12, // label
+ OPT_M = 1 << 13,
+ OPT_O = 1 << 14,
+ OPT_r = 1 << 15,
+ OPT_E = 1 << 16,
+ OPT_T = 1 << 17,
+ OPT_U = 1 << 18,
+ OPT_j = 1 << 19,
+ OPT_n = 1 << 20, // dry run: do not write anything
+ OPT_q = 1 << 21,
+ OPT_v = 1 << 22,
+ OPT_F = 1 << 23,
+ OPT_S = 1 << 24,
+ //OPT_V = 1 << 25, // -V version. bbox applets don't support that
+};
+
+int mkfs_ext2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mkfs_ext2_main(int argc UNUSED_PARAM, char **argv)
+{
+ unsigned i, pos, n;
+ unsigned bs, bpi;
+ unsigned blocksize, blocksize_log2;
+ unsigned inodesize, user_inodesize;
+ unsigned reserved_percent = 5;
+ unsigned long long kilobytes;
+ uint32_t nblocks, nblocks_full;
+ uint32_t nreserved;
+ uint32_t ngroups;
+ uint32_t bytes_per_inode;
+ uint32_t first_block;
+ uint32_t inodes_per_group;
+ uint32_t group_desc_blocks;
+ uint32_t inode_table_blocks;
+ uint32_t lost_and_found_blocks;
+ time_t timestamp;
+ const char *label = "";
+ struct stat st;
+ struct ext2_super_block *sb; // superblock
+ struct ext2_group_desc *gd; // group descriptors
+ struct ext2_inode *inode;
+ struct ext2_dir *dir;
+ uint8_t *buf;
+
+ // using global "option_mask32" instead of local "opts":
+ // we are register starved here
+ opt_complementary = "-1:b+:i+:I+:m+";
+ /*opts =*/ getopt32(argv, "cl:b:f:i:I:J:G:N:m:o:g:L:M:O:r:E:T:U:jnqvFS",
+ /*lbfi:*/ NULL, &bs, NULL, &bpi,
+ /*IJGN:*/ &user_inodesize, NULL, NULL, NULL,
+ /*mogL:*/ &reserved_percent, NULL, NULL, &label,
+ /*MOrE:*/ NULL, NULL, NULL, NULL,
+ /*TU:*/ NULL, NULL);
+ argv += optind; // argv[0] -- device
+
+ // open the device, check the device is a block device
+ xmove_fd(xopen(argv[0], O_WRONLY), fd);
+ xfstat(fd, &st, argv[0]);
+ if (!S_ISBLK(st.st_mode) && !(option_mask32 & OPT_F))
+ bb_error_msg_and_die("%s: not a block device", argv[0]);
+
+ // check if it is mounted
+ // N.B. what if we format a file? find_mount_point will return false negative since
+ // it is loop block device which is mounted!
+ if (find_mount_point(argv[0], 0))
+ bb_error_msg_and_die("can't format mounted filesystem");
+
+ // get size in kbytes
+ kilobytes = get_volume_size_in_bytes(fd, argv[1], 1024, /*extend:*/ !(option_mask32 & OPT_n)) / 1024;
+
+ bytes_per_inode = 16384;
+ if (kilobytes < 512*1024)
+ bytes_per_inode = 4096;
+ if (kilobytes < 3*1024)
+ bytes_per_inode = 8192;
+ if (option_mask32 & OPT_i)
+ bytes_per_inode = bpi;
+
+ // Determine block size and inode size
+ // block size is a multiple of 1024
+ // inode size is a multiple of 128
+ blocksize = 1024;
+ inodesize = sizeof(struct ext2_inode); // 128
+ if (kilobytes >= 512*1024) { // mke2fs 1.41.9 compat
+ blocksize = 4096;
+ inodesize = 256;
+ }
+ if (EXT2_MAX_BLOCK_SIZE > 4096) {
+ // kilobytes >> 22 == size in 4gigabyte chunks.
+ // if size >= 16k gigs, blocksize must be increased.
+ // Try "mke2fs -F image $((16 * 1024*1024*1024))"
+ while ((kilobytes >> 22) >= blocksize)
+ blocksize *= 2;
+ }
+ if (option_mask32 & OPT_b)
+ blocksize = bs;
+ if (blocksize < EXT2_MIN_BLOCK_SIZE
+ || blocksize > EXT2_MAX_BLOCK_SIZE
+ || (blocksize & (blocksize - 1)) // not power of 2
+ ) {
+ bb_error_msg_and_die("blocksize %u is bad", blocksize);
+ }
+ // Do we have custom inode size?
+ if (option_mask32 & OPT_I) {
+ if (user_inodesize < sizeof(*inode)
+ || user_inodesize > blocksize
+ || (user_inodesize & (user_inodesize - 1)) // not power of 2
+ ) {
+ bb_error_msg("-%c is bad", 'I');
+ } else {
+ inodesize = user_inodesize;
+ }
+ }
+
+ if ((int32_t)bytes_per_inode < blocksize)
+ bb_error_msg_and_die("-%c is bad", 'i');
+ // number of bits in one block, i.e. 8*blocksize
+#define blocks_per_group (8 * blocksize)
+ first_block = (EXT2_MIN_BLOCK_SIZE == blocksize);
+ blocksize_log2 = int_log2(blocksize);
+
+ // Determine number of blocks
+ kilobytes >>= (blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE);
+ nblocks = kilobytes;
+ if (nblocks != kilobytes)
+ bb_error_msg_and_die("block count doesn't fit in 32 bits");
+#define kilobytes kilobytes_unused_after_this
+ // Experimentally, standard mke2fs won't work on images smaller than 60k
+ if (nblocks < 60)
+ bb_error_msg_and_die("need >= 60 blocks");
+
+ // How many reserved blocks?
+ if (reserved_percent > 50)
+ bb_error_msg_and_die("-%c is bad", 'm');
+ nreserved = (uint64_t)nblocks * reserved_percent / 100;
+
+ // N.B. killing e2fsprogs feature! Unused blocks don't account in calculations
+ nblocks_full = nblocks;
+
+ // If last block group is too small, nblocks may be decreased in order
+ // to discard it, and control returns here to recalculate some
+ // parameters.
+ // Note: blocksize and bytes_per_inode are never recalculated.
+ retry:
+ // N.B. a block group can have no more than blocks_per_group blocks
+ ngroups = div_roundup(nblocks - first_block, blocks_per_group);
+
+ group_desc_blocks = div_roundup(ngroups, blocksize / sizeof(*gd));
+ // TODO: reserved blocks must be marked as such in the bitmaps,
+ // or resulting filesystem is corrupt
+ if (ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT) {
+ /*
+ * From e2fsprogs: Calculate the number of GDT blocks to reserve for online
+ * filesystem growth.
+ * The absolute maximum number of GDT blocks we can reserve is determined by
+ * the number of block pointers that can fit into a single block.
+ * We set it at 1024x the current filesystem size, or
+ * the upper block count limit (2^32), whichever is lower.
+ */
+ uint32_t reserved_group_desc_blocks = 0xFFFFFFFF; // maximum block number
+ if (nblocks < reserved_group_desc_blocks / 1024)
+ reserved_group_desc_blocks = nblocks * 1024;
+ reserved_group_desc_blocks = div_roundup(reserved_group_desc_blocks - first_block, blocks_per_group);
+ reserved_group_desc_blocks = div_roundup(reserved_group_desc_blocks, blocksize / sizeof(*gd)) - group_desc_blocks;
+ if (reserved_group_desc_blocks > blocksize / sizeof(uint32_t))
+ reserved_group_desc_blocks = blocksize / sizeof(uint32_t);
+ //TODO: STORE_LE(sb->s_reserved_gdt_blocks, reserved_group_desc_blocks);
+ group_desc_blocks += reserved_group_desc_blocks;
+ }
+
+ {
+ // N.B. e2fsprogs does as follows!
+ uint32_t overhead, remainder;
+ // ninodes is the max number of inodes in this filesystem
+ uint32_t ninodes = ((uint64_t) nblocks_full * blocksize) / bytes_per_inode;
+ if (ninodes < EXT2_GOOD_OLD_FIRST_INO+1)
+ ninodes = EXT2_GOOD_OLD_FIRST_INO+1;
+ inodes_per_group = div_roundup(ninodes, ngroups);
+ // minimum number because the first EXT2_GOOD_OLD_FIRST_INO-1 are reserved
+ if (inodes_per_group < 16)
+ inodes_per_group = 16;
+ // a block group can't have more inodes than blocks
+ if (inodes_per_group > blocks_per_group)
+ inodes_per_group = blocks_per_group;
+ // adjust inodes per group so they completely fill the inode table blocks in the descriptor
+ inodes_per_group = (div_roundup(inodes_per_group * inodesize, blocksize) * blocksize) / inodesize;
+ // make sure the number of inodes per group is a multiple of 8
+ inodes_per_group &= ~7;
+ inode_table_blocks = div_roundup(inodes_per_group * inodesize, blocksize);
+
+ // to be useful, lost+found should occupy at least 2 blocks (but not exceeding 16*1024 bytes),
+ // and at most EXT2_NDIR_BLOCKS. So reserve these blocks right now
+ /* Or e2fsprogs comment verbatim (what does it mean?):
+ * Ensure that lost+found is at least 2 blocks, so we always
+ * test large empty blocks for big-block filesystems. */
+ lost_and_found_blocks = MIN(EXT2_NDIR_BLOCKS, 16 >> (blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE));
+
+ // the last group needs more attention: isn't it too small for possible overhead?
+ overhead = (has_super(ngroups - 1) ? (1/*sb*/ + group_desc_blocks) : 0) + 1/*bbmp*/ + 1/*ibmp*/ + inode_table_blocks;
+ remainder = (nblocks - first_block) % blocks_per_group;
+ ////can't happen, nblocks >= 60 guarantees this
+ ////if ((1 == ngroups)
+ //// && remainder
+ //// && (remainder < overhead + 1/* "/" */ + lost_and_found_blocks)
+ ////) {
+ //// bb_error_msg_and_die("way small device");
+ ////}
+
+ // Standard mke2fs uses 50. Looks like a bug in our calculation
+ // of "remainder" or "overhead" - we don't match standard mke2fs
+ // when we transition from one group to two groups
+ // (a bit after 8M image size), but it works for two->three groups
+ // transition (at 16M).
+ if (remainder && (remainder < overhead + 50)) {
+//bb_info_msg("CHOP[%u]", remainder);
+ nblocks -= remainder;
+ goto retry;
+ }
+ }
+
+ if (nblocks_full - nblocks)
+ printf("warning: %u blocks unused\n\n", nblocks_full - nblocks);
+ printf(
+ "Filesystem label=%s\n"
+ "OS type: Linux\n"
+ "Block size=%u (log=%u)\n"
+ "Fragment size=%u (log=%u)\n"
+ "%u inodes, %u blocks\n"
+ "%u blocks (%u%%) reserved for the super user\n"
+ "First data block=%u\n"
+ "Maximum filesystem blocks=%u\n"
+ "%u block groups\n"
+ "%u blocks per group, %u fragments per group\n"
+ "%u inodes per group"
+ , label
+ , blocksize, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE
+ , blocksize, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE
+ , inodes_per_group * ngroups, nblocks
+ , nreserved, reserved_percent
+ , first_block
+ , group_desc_blocks * (blocksize / (unsigned)sizeof(*gd)) * blocks_per_group
+ , ngroups
+ , blocks_per_group, blocks_per_group
+ , inodes_per_group
+ );
+ {
+ const char *fmt = "\nSuperblock backups stored on blocks:\n"
+ "\t%u";
+ pos = first_block;
+ for (i = 1; i < ngroups; i++) {
+ pos += blocks_per_group;
+ if (has_super(i)) {
+ printf(fmt, (unsigned)pos);
+ fmt = ", %u";
+ }
+ }
+ }
+ bb_putchar('\n');
+
+ if (option_mask32 & OPT_n) {
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(fd);
+ return EXIT_SUCCESS;
+ }
+
+ // TODO: 3/5 refuse if mounted
+ // TODO: 4/5 compat options
+ // TODO: 1/5 sanity checks
+ // TODO: 0/5 more verbose error messages
+ // TODO: 4/5 bigendianness: recheck, wait for ARM reporters
+ // TODO: 2/5 reserved GDT: how to mark but not allocate?
+ // TODO: 3/5 dir_index?
+
+ // fill the superblock
+ sb = xzalloc(1024);
+ STORE_LE(sb->s_rev_level, EXT2_DYNAMIC_REV); // revision 1 filesystem
+ STORE_LE(sb->s_magic, EXT2_SUPER_MAGIC);
+ STORE_LE(sb->s_inode_size, inodesize);
+ // set "Required extra isize" and "Desired extra isize" fields to 28
+ if (inodesize != sizeof(*inode)) {
+ STORE_LE(sb->s_min_extra_isize, 0x001c);
+ STORE_LE(sb->s_want_extra_isize, 0x001c);
+ }
+ STORE_LE(sb->s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
+ STORE_LE(sb->s_log_block_size, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE);
+ STORE_LE(sb->s_log_frag_size, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE);
+ // first 1024 bytes of the device are for boot record. If block size is 1024 bytes, then
+ // the first block is 1, otherwise 0
+ STORE_LE(sb->s_first_data_block, first_block);
+ // block and inode bitmaps occupy no more than one block, so maximum number of blocks is
+ STORE_LE(sb->s_blocks_per_group, blocks_per_group);
+ STORE_LE(sb->s_frags_per_group, blocks_per_group);
+ // blocks
+ STORE_LE(sb->s_blocks_count, nblocks);
+ // reserve blocks for superuser
+ STORE_LE(sb->s_r_blocks_count, nreserved);
+ // ninodes
+ STORE_LE(sb->s_inodes_per_group, inodes_per_group);
+ STORE_LE(sb->s_inodes_count, inodes_per_group * ngroups);
+ STORE_LE(sb->s_free_inodes_count, inodes_per_group * ngroups - EXT2_GOOD_OLD_FIRST_INO);
+ // timestamps
+ timestamp = time(NULL);
+ STORE_LE(sb->s_mkfs_time, timestamp);
+ STORE_LE(sb->s_wtime, timestamp);
+ STORE_LE(sb->s_lastcheck, timestamp);
+ // misc. Values are chosen to match mke2fs 1.41.9
+ STORE_LE(sb->s_state, 1); // TODO: what's 1?
+ STORE_LE(sb->s_creator_os, EXT2_OS_LINUX);
+ STORE_LE(sb->s_checkinterval, 24*60*60 * 180); // 180 days
+ STORE_LE(sb->s_errors, EXT2_ERRORS_DEFAULT);
+ // mke2fs 1.41.9 also sets EXT3_FEATURE_COMPAT_RESIZE_INODE
+ // and if >= 0.5GB, EXT3_FEATURE_RO_COMPAT_LARGE_FILE.
+ // we use values which match "mke2fs -O ^resize_inode":
+ // in this case 1.41.9 never sets EXT3_FEATURE_RO_COMPAT_LARGE_FILE.
+ STORE_LE(sb->s_feature_compat, EXT2_FEATURE_COMPAT_SUPP
+ | (EXT2_FEATURE_COMPAT_RESIZE_INO * ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT)
+ | (EXT2_FEATURE_COMPAT_DIR_INDEX * ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX)
+ );
+ STORE_LE(sb->s_feature_incompat, EXT2_FEATURE_INCOMPAT_FILETYPE);
+ STORE_LE(sb->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER);
+ STORE_LE(sb->s_flags, EXT2_FLAGS_UNSIGNED_HASH * ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX);
+ generate_uuid(sb->s_uuid);
+ if (ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX) {
+ STORE_LE(sb->s_def_hash_version, EXT2_HASH_HALF_MD4);
+ generate_uuid((uint8_t *)sb->s_hash_seed);
+ }
+ /*
+ * From e2fsprogs: add "jitter" to the superblock's check interval so that we
+ * don't check all the filesystems at the same time. We use a
+ * kludgy hack of using the UUID to derive a random jitter value.
+ */
+ STORE_LE(sb->s_max_mnt_count,
+ EXT2_DFL_MAX_MNT_COUNT
+ + (sb->s_uuid[ARRAY_SIZE(sb->s_uuid)-1] % EXT2_DFL_MAX_MNT_COUNT));
+
+ // write the label
+ safe_strncpy((char *)sb->s_volume_name, label, sizeof(sb->s_volume_name));
+
+ // calculate filesystem skeleton structures
+ gd = xzalloc(group_desc_blocks * blocksize);
+ buf = xmalloc(blocksize);
+ sb->s_free_blocks_count = 0;
+ for (i = 0, pos = first_block, n = nblocks - first_block;
+ i < ngroups;
+ i++, pos += blocks_per_group, n -= blocks_per_group
+ ) {
+ uint32_t overhead = pos + (has_super(i) ? (1/*sb*/ + group_desc_blocks) : 0);
+ uint32_t free_blocks;
+ // fill group descriptors
+ STORE_LE(gd[i].bg_block_bitmap, overhead + 0);
+ STORE_LE(gd[i].bg_inode_bitmap, overhead + 1);
+ STORE_LE(gd[i].bg_inode_table, overhead + 2);
+ overhead = overhead - pos + 1/*bbmp*/ + 1/*ibmp*/ + inode_table_blocks;
+ gd[i].bg_free_inodes_count = inodes_per_group;
+ //STORE_LE(gd[i].bg_used_dirs_count, 0);
+ // N.B. both "/" and "/lost+found" are within the first block group
+ // "/" occupies 1 block, "/lost+found" occupies lost_and_found_blocks...
+ if (0 == i) {
+ // ... thus increased overhead for the first block group ...
+ overhead += 1 + lost_and_found_blocks;
+ // ... and 2 used directories
+ STORE_LE(gd[i].bg_used_dirs_count, 2);
+ // well known reserved inodes belong to the first block too
+ gd[i].bg_free_inodes_count -= EXT2_GOOD_OLD_FIRST_INO;
+ }
+
+ // cache free block count of the group
+ free_blocks = (n < blocks_per_group ? n : blocks_per_group) - overhead;
+
+ // mark preallocated blocks as allocated
+//bb_info_msg("ALLOC: [%u][%u][%u]", blocksize, overhead, blocks_per_group - (free_blocks + overhead));
+ allocate(buf, blocksize,
+ // reserve "overhead" blocks
+ overhead,
+ // mark unused trailing blocks
+ blocks_per_group - (free_blocks + overhead)
+ );
+ // dump block bitmap
+ PUT((uint64_t)(FETCH_LE32(gd[i].bg_block_bitmap)) * blocksize, buf, blocksize);
+ STORE_LE(gd[i].bg_free_blocks_count, free_blocks);
+
+ // mark preallocated inodes as allocated
+ allocate(buf, blocksize,
+ // mark reserved inodes
+ inodes_per_group - gd[i].bg_free_inodes_count,
+ // mark unused trailing inodes
+ blocks_per_group - inodes_per_group
+ );
+ // dump inode bitmap
+ //PUT((uint64_t)(FETCH_LE32(gd[i].bg_block_bitmap)) * blocksize, buf, blocksize);
+ //but it's right after block bitmap, so we can just:
+ xwrite(fd, buf, blocksize);
+ STORE_LE(gd[i].bg_free_inodes_count, gd[i].bg_free_inodes_count);
+
+ // count overall free blocks
+ sb->s_free_blocks_count += free_blocks;
+ }
+ STORE_LE(sb->s_free_blocks_count, sb->s_free_blocks_count);
+
+ // dump filesystem skeleton structures
+// printf("Writing superblocks and filesystem accounting information: ");
+ for (i = 0, pos = first_block; i < ngroups; i++, pos += blocks_per_group) {
+ // dump superblock and group descriptors and their backups
+ if (has_super(i)) {
+ // N.B. 1024 byte blocks are special
+ PUT(((uint64_t)pos * blocksize) + ((0 == i && 1024 != blocksize) ? 1024 : 0),
+ sb, 1024);
+ PUT(((uint64_t)pos * blocksize) + blocksize,
+ gd, group_desc_blocks * blocksize);
+ }
+ }
+
+ // zero boot sectors
+ memset(buf, 0, blocksize);
+ // Disabled: standard mke2fs doesn't do this, and
+ // on SPARC this destroys Sun disklabel.
+ // Users who need/want zeroing can easily do it with dd.
+ //PUT(0, buf, 1024); // N.B. 1024 <= blocksize, so buf[0..1023] contains zeros
+
+ // zero inode tables
+ for (i = 0; i < ngroups; ++i)
+ for (n = 0; n < inode_table_blocks; ++n)
+ PUT((uint64_t)(FETCH_LE32(gd[i].bg_inode_table) + n) * blocksize,
+ buf, blocksize);
+
+ // prepare directory inode
+ inode = (struct ext2_inode *)buf;
+ STORE_LE(inode->i_mode, S_IFDIR | S_IRWXU | S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH);
+ STORE_LE(inode->i_mtime, timestamp);
+ STORE_LE(inode->i_atime, timestamp);
+ STORE_LE(inode->i_ctime, timestamp);
+ STORE_LE(inode->i_size, blocksize);
+ // inode->i_blocks stores the number of 512 byte data blocks
+ // (512, because it goes directly to struct stat without scaling)
+ STORE_LE(inode->i_blocks, blocksize / 512);
+
+ // dump root dir inode
+ STORE_LE(inode->i_links_count, 3); // "/.", "/..", "/lost+found/.." point to this inode
+ STORE_LE(inode->i_block[0], FETCH_LE32(gd[0].bg_inode_table) + inode_table_blocks);
+ PUT(((uint64_t)FETCH_LE32(gd[0].bg_inode_table) * blocksize) + (EXT2_ROOT_INO-1) * inodesize,
+ buf, inodesize);
+
+ // dump lost+found dir inode
+ STORE_LE(inode->i_links_count, 2); // both "/lost+found" and "/lost+found/." point to this inode
+ STORE_LE(inode->i_size, lost_and_found_blocks * blocksize);
+ STORE_LE(inode->i_blocks, (lost_and_found_blocks * blocksize) / 512);
+ n = FETCH_LE32(inode->i_block[0]) + 1;
+ for (i = 0; i < lost_and_found_blocks; ++i)
+ STORE_LE(inode->i_block[i], i + n); // use next block
+//bb_info_msg("LAST BLOCK USED[%u]", i + n);
+ PUT(((uint64_t)FETCH_LE32(gd[0].bg_inode_table) * blocksize) + (EXT2_GOOD_OLD_FIRST_INO-1) * inodesize,
+ buf, inodesize);
+
+ // dump directories
+ memset(buf, 0, blocksize);
+ dir = (struct ext2_dir *)buf;
+
+ // dump 2nd+ blocks of "/lost+found"
+ STORE_LE(dir->rec_len1, blocksize); // e2fsck 1.41.4 compat (1.41.9 does not need this)
+ for (i = 1; i < lost_and_found_blocks; ++i)
+ PUT((uint64_t)(FETCH_LE32(gd[0].bg_inode_table) + inode_table_blocks + 1+i) * blocksize,
+ buf, blocksize);
+
+ // dump 1st block of "/lost+found"
+ STORE_LE(dir->inode1, EXT2_GOOD_OLD_FIRST_INO);
+ STORE_LE(dir->rec_len1, 12);
+ STORE_LE(dir->name_len1, 1);
+ STORE_LE(dir->file_type1, EXT2_FT_DIR);
+ dir->name1[0] = '.';
+ STORE_LE(dir->inode2, EXT2_ROOT_INO);
+ STORE_LE(dir->rec_len2, blocksize - 12);
+ STORE_LE(dir->name_len2, 2);
+ STORE_LE(dir->file_type2, EXT2_FT_DIR);
+ dir->name2[0] = '.'; dir->name2[1] = '.';
+ PUT((uint64_t)(FETCH_LE32(gd[0].bg_inode_table) + inode_table_blocks + 1) * blocksize, buf, blocksize);
+
+ // dump root dir block
+ STORE_LE(dir->inode1, EXT2_ROOT_INO);
+ STORE_LE(dir->rec_len2, 12);
+ STORE_LE(dir->inode3, EXT2_GOOD_OLD_FIRST_INO);
+ STORE_LE(dir->rec_len3, blocksize - 12 - 12);
+ STORE_LE(dir->name_len3, 10);
+ STORE_LE(dir->file_type3, EXT2_FT_DIR);
+ strcpy(dir->name3, "lost+found");
+ PUT((uint64_t)(FETCH_LE32(gd[0].bg_inode_table) + inode_table_blocks + 0) * blocksize, buf, blocksize);
+
+ // cleanup
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(buf);
+ free(gd);
+ free(sb);
+ }
+
+ xclose(fd);
+ return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/util-linux/mkfs_ext2.txt b/ap/app/busybox/src/util-linux/mkfs_ext2.txt
new file mode 100644
index 0000000..273d5b6
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/mkfs_ext2.txt
@@ -0,0 +1,77 @@
+Difference between bbox mke2fs and standard one (dumpe2fs comparison):
+
+[upd: inode size has been fixed since then]
+
+Two significant differences:
+- standard mke2fs has resize_inode feature and thus has reserved GDT blocks,
+ which decreases free blocks;
+- inode size: 128/256 (since 679807k is >0.5G, standard mke2fs uses "big" inodes)
+ this affects inode table in block groups
+
+Filesystem volume name: <none> Filesystem volume name: <none>
+Last mounted on: <not available> Last mounted on: <not available>
+Filesystem UUID: f4839760-c89b-44b7-ac52-08b4e326c0b4 Filesystem UUID: 71179558-8c8e-4a56-ad54-018008f5c358
+Filesystem magic number: 0xEF53 Filesystem magic number: 0xEF53
+Filesystem revision #: 1 (dynamic) Filesystem revision #: 1 (dynamic)
+Filesystem features: ext_attr dir_index filetype sparse_super Filesystem features: ext_attr resize_inode dir_index filetype sparse_super large_file
+Filesystem flags: signed_directory_hash Filesystem flags: signed_directory_hash
+Default mount options: (none) Default mount options: (none)
+Filesystem state: clean Filesystem state: clean
+Errors behavior: Continue Errors behavior: Continue
+Filesystem OS type: Linux Filesystem OS type: Linux
+Inode count: 42624 Inode count: 42528
+Block count: 169951 Block count: 169951
+Reserved block count: 8497 Reserved block count: 8497
+Free blocks: 168594 Free blocks: 167103
+Free inodes: 42613 Free inodes: 42517
+First block: 0 First block: 0
+Block size: 4096 Block size: 4096
+Fragment size: 4096 Fragment size: 4096
+ Reserved GDT blocks: 41
+Blocks per group: 32768 Blocks per group: 32768
+Fragments per group: 32768 Fragments per group: 32768
+Inodes per group: 7104 Inodes per group: 7088
+Inode blocks per group: 222 Inode blocks per group: 443
+Filesystem created: Wed Oct 21 13:40:55 2009 Filesystem created: Wed Oct 21 13:40:55 2009
+Last mount time: n/a Last mount time: n/a
+Last write time: Wed Oct 21 13:40:55 2009 Last write time: Wed Oct 21 13:40:55 2009
+Mount count: 0 Mount count: 0
+Maximum mount count: 20 Maximum mount count: 37
+Last checked: Wed Oct 21 13:40:55 2009 Last checked: Wed Oct 21 13:40:55 2009
+Check interval: 15552000 (6 months) Check interval: 15552000 (6 months)
+Next check after: Mon Apr 19 13:40:55 2010 Next check after: Mon Apr 19 13:40:55 2010
+Reserved blocks uid: 0 (user root) Reserved blocks uid: 0 (user root)
+Reserved blocks gid: 0 (group root) Reserved blocks gid: 0 (group root)
+First inode: 11 First inode: 11
+Inode size: 128 Inode size: 256
+ Required extra isize: 28
+ Desired extra isize: 28
+Default directory hash: half_md4 Default directory hash: half_md4
+Directory Hash Seed: ff94d047-c9ca-4fe5-b553-937a76101a89 Directory Hash Seed: c270fd43-9868-4a92-ae99-050098e12835
+
+
+Group 0: (Blocks 0-32767) Group 0: (Blocks 0-32767)
+ Primary superblock at 0, Group descriptors at 1-1 Primary superblock at 0, Group descriptors at 1-1
+ Reserved GDT blocks at 2-42
+ Block bitmap at 2 (+2), Inode bitmap at 3 (+3) Block bitmap at 43 (+43), Inode bitmap at 44 (+44)
+ Inode table at 4-225 (+4) Inode table at 45-487 (+45)
+ 32537 free blocks, 7093 free inodes, 2 directories 32274 free blocks, 7077 free inodes, 2 directories
+ Free blocks: 231-32767 Free blocks: 494-32767
+ Free inodes: 12-7104 Free inodes: 12-7088
+
+Group 1: (Blocks 32768-65535) Group 1: (Blocks 32768-65535)
+ Backup superblock at 32768, Group descriptors at 32769-32769 Backup superblock at 32768, Group descriptors at 32769-32769
+ Reserved GDT blocks at 32770-32810
+ Block bitmap at 32770 (+2), Inode bitmap at 32771 (+3) Block bitmap at 32811 (+43), Inode bitmap at 32812 (+44)
+ Inode table at 32772-32993 (+4) Inode table at 32813-33255 (+45)
+ 32542 free blocks, 7104 free inodes, 0 directories 32280 free blocks, 7088 free inodes, 0 directories
+ Free blocks: 32994-65535 Free blocks: 33256-65535
+ Free inodes: 7105-14208 Free inodes: 7089-14176
+
+Group 2: (Blocks 65536-98303) Group 2: (Blocks 65536-98303)
+ Block bitmap at 65536 (+0), Inode bitmap at 65537 (+1) Block bitmap at 65536 (+0), Inode bitmap at 65537 (+1)
+ Inode table at 65538-65759 (+2) Inode table at 65538-65980 (+2)
+ 32544 free blocks, 7104 free inodes, 0 directories 32323 free blocks, 7088 free inodes, 0 directories
+ Free blocks: 65760-98303 Free blocks: 65981-98303
+ Free inodes: 14209-21312 Free inodes: 14177-21264
+...
diff --git a/ap/app/busybox/src/util-linux/mkfs_ext2_test.sh b/ap/app/busybox/src/util-linux/mkfs_ext2_test.sh
new file mode 100755
index 0000000..f5347cc
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/mkfs_ext2_test.sh
@@ -0,0 +1,104 @@
+#!/bin/sh
+
+# Disabling features we do not match exactly:
+system_mke2fs='/sbin/mke2fs -O ^resize_inode'
+bbox_mke2fs='./busybox mke2fs'
+
+gen_image() { # params: mke2fs_invocation image_name
+ >$2
+ dd seek=$((kilobytes-1)) bs=1K count=1 </dev/zero of=$2 >/dev/null 2>&1 || exit 1
+ $1 -F $2 $kilobytes >$2.raw_out 2>&1 || return 1
+ cat $2.raw_out \
+ | grep -v '^mke2fs [0-9]*\.[0-9]*\.[0-9]* ' \
+ | grep -v '^Maximum filesystem' \
+ | grep -v '^Writing inode tables' \
+ | grep -v '^Writing superblocks and filesystem accounting information' \
+ | grep -v '^This filesystem will be automatically checked every' \
+ | grep -v '^180 days, whichever comes first' \
+ | sed 's/blocks* unused./blocks unused/' \
+ | sed 's/block groups*/block groups/' \
+ | sed 's/ *$//' \
+ | sed 's/blocks (.*%) reserved/blocks reserved/' \
+ | grep -v '^$' \
+ >$2.out
+}
+
+test_mke2fs() {
+ echo Testing $kilobytes
+
+ gen_image "$system_mke2fs" image_std || return 1
+ gen_image "$bbox_mke2fs" image_bb || return 1
+
+ diff -ua image_bb.out image_std.out >image.out.diff || {
+ cat image.out.diff
+ return 1
+ }
+
+ e2fsck -f -n image_bb >image_bb_e2fsck.out 2>&1 || {
+ echo "e2fsck error on image_bb"
+ cat image_bb_e2fsck.out
+ exit 1
+ }
+}
+
+# -:bbox +:standard
+
+# kilobytes=60 is the minimal allowed size
+kilobytes=60
+while true; do
+ test_mke2fs || exit 1
+ : $((kilobytes++))
+ test $kilobytes = 200 && break
+done
+
+# Transition from one block group to two
+# fails in [8378..8410] range unless -O ^resize_inode
+kilobytes=$((1 * 8*1024 - 50))
+while true; do
+ test_mke2fs || exit 1
+ : $((kilobytes++))
+ test $kilobytes = $((1 * 8*1024 + 300)) && break
+done
+
+# Transition from 2 block groups to 3
+# works
+kilobytes=$((2 * 8*1024 - 50))
+while true; do
+ test_mke2fs || exit 1
+ : $((kilobytes++))
+ test $kilobytes = $((2 * 8*1024 + 400)) && break
+done
+
+# Transition from 3 block groups to 4
+# fails in [24825..24922] range unless -O ^resize_inode
+kilobytes=$((3 * 8*1024 - 50))
+while true; do
+ test_mke2fs || exit 1
+ : $((kilobytes++))
+ test $kilobytes = $((3 * 8*1024 + 500)) && break
+done
+
+# Transition from 4 block groups to 5
+# works
+kilobytes=$((4 * 8*1024 - 50))
+while true; do
+ test_mke2fs || exit 1
+ : $((kilobytes++))
+ test $kilobytes = $((4 * 8*1024 + 600)) && break
+done
+
+# Transition from 5 block groups to 6
+# fails in [41230..41391] range unless -O ^resize_inode
+kilobytes=$((5 * 8*1024 - 50))
+while true; do
+ test_mke2fs || exit 1
+ : $((kilobytes++))
+ test $kilobytes = $((5 * 8*1024 + 700)) && break
+done
+exit
+
+# Random sizes
+while true; do
+ kilobytes=$(( (RANDOM*RANDOM) % 5000000 + 60))
+ test_mke2fs || exit 1
+done
diff --git a/ap/app/busybox/src/util-linux/mkfs_minix.c b/ap/app/busybox/src/util-linux/mkfs_minix.c
new file mode 100644
index 0000000..59d7d23
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/mkfs_minix.c
@@ -0,0 +1,740 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mkfs.c - make a linux (minix) file-system.
+ *
+ * (C) 1991 Linus Torvalds.
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+/*
+ * DD.MM.YY
+ *
+ * 24.11.91 - Time began. Used the fsck sources to get started.
+ *
+ * 25.11.91 - Corrected some bugs. Added support for ".badblocks"
+ * The algorithm for ".badblocks" is a bit weird, but
+ * it should work. Oh, well.
+ *
+ * 25.01.92 - Added the -l option for getting the list of bad blocks
+ * out of a named file. (Dave Rivers, rivers@ponds.uucp)
+ *
+ * 28.02.92 - Added %-information when using -c.
+ *
+ * 28.02.93 - Added support for other namelengths than the original
+ * 14 characters so that I can test the new kernel routines..
+ *
+ * 09.10.93 - Make exit status conform to that required by fsutil
+ * (Rik Faith, faith@cs.unc.edu)
+ *
+ * 31.10.93 - Added inode request feature, for backup floppies: use
+ * 32 inodes, for a news partition use more.
+ * (Scott Heavner, sdh@po.cwru.edu)
+ *
+ * 03.01.94 - Added support for file system valid flag.
+ * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu)
+ *
+ * 30.10.94 - added support for v2 filesystem
+ * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
+ *
+ * 09.11.94 - Added test to prevent overwrite of mounted fs adapted
+ * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs
+ * program. (Daniel Quinlan, quinlan@yggdrasil.com)
+ *
+ * 03.20.95 - Clear first 512 bytes of filesystem to make certain that
+ * the filesystem is not misidentified as a MS-DOS FAT filesystem.
+ * (Daniel Quinlan, quinlan@yggdrasil.com)
+ *
+ * 02.07.96 - Added small patch from Russell King to make the program a
+ * good deal more portable (janl@math.uio.no)
+ *
+ * Usage: mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks]
+ *
+ * -c for readability checking (SLOW!)
+ * -l for getting a list of bad blocks from a file.
+ * -n for namelength (currently the kernel only uses 14 or 30)
+ * -i for number of inodes
+ * -v for v2 filesystem
+ *
+ * The device may be a block device or a image of one, but this isn't
+ * enforced (but it's not much fun on a character device :-).
+ *
+ * Modified for BusyBox by Erik Andersen <andersen@debian.org> --
+ * removed getopt based parser and added a hand rolled one.
+ */
+
+//usage:#define mkfs_minix_trivial_usage
+//usage: "[-c | -l FILE] [-nXX] [-iXX] BLOCKDEV [KBYTES]"
+//usage:#define mkfs_minix_full_usage "\n\n"
+//usage: "Make a MINIX filesystem\n"
+//usage: "\n -c Check device for bad blocks"
+//usage: "\n -n [14|30] Maximum length of filenames"
+//usage: "\n -i INODES Number of inodes for the filesystem"
+//usage: "\n -l FILE Read bad blocks list from FILE"
+//usage: "\n -v Make version 2 filesystem"
+
+#include "libbb.h"
+#include <mntent.h>
+
+#include "minix.h"
+
+/* 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
+
+enum {
+ MAX_GOOD_BLOCKS = 512,
+ TEST_BUFFER_BLOCKS = 16,
+};
+
+#if !ENABLE_FEATURE_MINIX2
+enum { version2 = 0 };
+#endif
+
+enum { dev_fd = 3 };
+
+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;
+}
+
+#define INODE_BUF1 (((struct minix1_inode*)G.inode_buffer) - 1)
+#define INODE_BUF2 (((struct minix2_inode*)G.inode_buffer) - 1)
+
+#define SB (*(struct minix_superblock*)G.superblock_buffer)
+
+#define SB_INODES (SB.s_ninodes)
+#define SB_IMAPS (SB.s_imap_blocks)
+#define SB_ZMAPS (SB.s_zmap_blocks)
+#define SB_FIRSTZONE (SB.s_firstdatazone)
+#define SB_ZONE_SIZE (SB.s_log_zone_size)
+#define SB_MAXSIZE (SB.s_max_size)
+#define SB_MAGIC (SB.s_magic)
+
+#if !ENABLE_FEATURE_MINIX2
+# define SB_ZONES (SB.s_nzones)
+# define INODE_BLOCKS div_roundup(SB_INODES, MINIX1_INODES_PER_BLOCK)
+#else
+# define SB_ZONES (version2 ? SB.s_zones : SB.s_nzones)
+# define INODE_BLOCKS div_roundup(SB_INODES, \
+ (version2 ? MINIX2_INODES_PER_BLOCK : MINIX1_INODES_PER_BLOCK))
+#endif
+
+#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
+#define NORM_FIRSTZONE (2 + SB_IMAPS + SB_ZMAPS + INODE_BLOCKS)
+
+/* Before you ask "where they come from?": */
+/* setbit/clrbit are supplied by sys/param.h */
+
+static int minix_bit(const char* a, unsigned i)
+{
+ return a[i >> 3] & (1<<(i & 7));
+}
+
+static void minix_setbit(char *a, unsigned i)
+{
+ setbit(a, i);
+}
+static void minix_clrbit(char *a, unsigned i)
+{
+ clrbit(a, i);
+}
+
+/* Note: do not assume 0/1, it is 0/nonzero */
+#define zone_in_use(x) minix_bit(G.zone_map,(x)-SB_FIRSTZONE+1)
+/*#define inode_in_use(x) minix_bit(G.inode_map,(x))*/
+
+#define mark_inode(x) minix_setbit(G.inode_map,(x))
+#define unmark_inode(x) minix_clrbit(G.inode_map,(x))
+#define mark_zone(x) minix_setbit(G.zone_map,(x)-SB_FIRSTZONE+1)
+#define unmark_zone(x) minix_clrbit(G.zone_map,(x)-SB_FIRSTZONE+1)
+
+#ifndef BLKGETSIZE
+# define BLKGETSIZE _IO(0x12,96) /* return device size */
+#endif
+
+
+static long valid_offset(int fd, int offset)
+{
+ char ch;
+
+ if (lseek(fd, offset, SEEK_SET) < 0)
+ return 0;
+ if (read(fd, &ch, 1) < 1)
+ return 0;
+ return 1;
+}
+
+static int count_blocks(int fd)
+{
+ int high, low;
+
+ low = 0;
+ for (high = 1; valid_offset(fd, high); high *= 2)
+ low = high;
+
+ while (low < high - 1) {
+ const int mid = (low + high) / 2;
+
+ if (valid_offset(fd, mid))
+ low = mid;
+ else
+ high = mid;
+ }
+ valid_offset(fd, 0);
+ return (low + 1);
+}
+
+static int get_size(const char *file)
+{
+ int fd;
+ long size;
+
+ fd = xopen(file, O_RDWR);
+ if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
+ close(fd);
+ return (size * 512);
+ }
+
+ size = count_blocks(fd);
+ close(fd);
+ return size;
+}
+
+static void write_tables(void)
+{
+ /* Mark the 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 = "can't 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 = "can't write superblock";
+ xwrite(dev_fd, G.superblock_buffer, BLOCK_SIZE);
+
+ msg_eol = "can't write inode map";
+ xwrite(dev_fd, G.inode_map, SB_IMAPS * BLOCK_SIZE);
+
+ msg_eol = "can't write zone map";
+ xwrite(dev_fd, G.zone_map, SB_ZMAPS * BLOCK_SIZE);
+
+ msg_eol = "can't write inodes";
+ xwrite(dev_fd, G.inode_buffer, INODE_BUFFER_SIZE);
+
+ msg_eol = "\n";
+}
+
+static void write_block(int blk, char *buffer)
+{
+ xlseek(dev_fd, blk * BLOCK_SIZE, SEEK_SET);
+ xwrite(dev_fd, buffer, BLOCK_SIZE);
+}
+
+static int get_free_block(void)
+{
+ int blk;
+
+ if (G.used_good_blocks + 1 >= MAX_GOOD_BLOCKS)
+ bb_error_msg_and_die("too many bad blocks");
+ if (G.used_good_blocks)
+ blk = G.good_blocks_table[G.used_good_blocks - 1] + 1;
+ else
+ blk = SB_FIRSTZONE;
+ while (blk < SB_ZONES && zone_in_use(blk))
+ blk++;
+ if (blk >= SB_ZONES)
+ bb_error_msg_and_die("not enough good blocks");
+ G.good_blocks_table[G.used_good_blocks] = blk;
+ G.used_good_blocks++;
+ return blk;
+}
+
+static void mark_good_blocks(void)
+{
+ int blk;
+
+ for (blk = 0; blk < G.used_good_blocks; blk++)
+ mark_zone(G.good_blocks_table[blk]);
+}
+
+static int next(int zone)
+{
+ if (!zone)
+ zone = SB_FIRSTZONE - 1;
+ while (++zone < SB_ZONES)
+ if (zone_in_use(zone))
+ return zone;
+ return 0;
+}
+
+static void make_bad_inode(void)
+{
+ struct minix1_inode *inode = &INODE_BUF1[MINIX_BAD_INO];
+ int i, j, zone;
+ int ind = 0, dind = 0;
+ /* 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 (!G.badblocks)
+ return;
+ mark_inode(MINIX_BAD_INO);
+ inode->i_nlinks = 1;
+ /* BTW, setting this makes all images different */
+ /* it's harder to check for bugs then - diff isn't helpful :(... */
+ inode->i_time = CUR_TIME;
+ inode->i_mode = S_IFREG + 0000;
+ inode->i_size = G.badblocks * BLOCK_SIZE;
+ zone = next(0);
+ for (i = 0; i < 7; i++) {
+ inode->i_zone[i] = zone;
+ if (!NEXT_BAD)
+ goto end_bad;
+ }
+ inode->i_zone[7] = ind = get_free_block();
+ memset(ind_block, 0, BLOCK_SIZE);
+ for (i = 0; i < 512; i++) {
+ ind_block[i] = zone;
+ if (!NEXT_BAD)
+ goto end_bad;
+ }
+ inode->i_zone[8] = dind = get_free_block();
+ memset(dind_block, 0, BLOCK_SIZE);
+ for (i = 0; i < 512; i++) {
+ write_block(ind, (char *) ind_block);
+ dind_block[i] = ind = get_free_block();
+ memset(ind_block, 0, BLOCK_SIZE);
+ for (j = 0; j < 512; j++) {
+ ind_block[j] = zone;
+ if (!NEXT_BAD)
+ goto end_bad;
+ }
+ }
+ bb_error_msg_and_die("too many bad blocks");
+ end_bad:
+ if (ind)
+ write_block(ind, (char *) ind_block);
+ if (dind)
+ write_block(dind, (char *) dind_block);
+#undef ind_block
+#undef dind_block
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void make_bad_inode2(void)
+{
+ struct minix2_inode *inode = &INODE_BUF2[MINIX_BAD_INO];
+ int i, j, zone;
+ int ind = 0, dind = 0;
+ /* 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 (!G.badblocks)
+ return;
+ mark_inode(MINIX_BAD_INO);
+ inode->i_nlinks = 1;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CUR_TIME;
+ inode->i_mode = S_IFREG + 0000;
+ inode->i_size = G.badblocks * BLOCK_SIZE;
+ zone = next(0);
+ for (i = 0; i < 7; i++) {
+ inode->i_zone[i] = zone;
+ if (!NEXT_BAD)
+ goto end_bad;
+ }
+ inode->i_zone[7] = ind = get_free_block();
+ memset(ind_block, 0, BLOCK_SIZE);
+ for (i = 0; i < 256; i++) {
+ ind_block[i] = zone;
+ if (!NEXT_BAD)
+ goto end_bad;
+ }
+ inode->i_zone[8] = dind = get_free_block();
+ memset(dind_block, 0, BLOCK_SIZE);
+ for (i = 0; i < 256; i++) {
+ write_block(ind, (char *) ind_block);
+ dind_block[i] = ind = get_free_block();
+ memset(ind_block, 0, BLOCK_SIZE);
+ for (j = 0; j < 256; j++) {
+ ind_block[j] = zone;
+ if (!NEXT_BAD)
+ goto end_bad;
+ }
+ }
+ /* Could make triple indirect block here */
+ bb_error_msg_and_die("too many bad blocks");
+ end_bad:
+ if (ind)
+ write_block(ind, (char *) ind_block);
+ if (dind)
+ write_block(dind, (char *) dind_block);
+#undef ind_block
+#undef dind_block
+}
+#else
+void make_bad_inode2(void);
+#endif
+
+static void make_root_inode(void)
+{
+ struct minix1_inode *inode = &INODE_BUF1[MINIX_ROOT_INO];
+
+ mark_inode(MINIX_ROOT_INO);
+ inode->i_zone[0] = get_free_block();
+ inode->i_nlinks = 2;
+ inode->i_time = CUR_TIME;
+ if (G.badblocks)
+ inode->i_size = 3 * G.dirsize;
+ else {
+ G.root_block[2 * G.dirsize] = '\0';
+ G.root_block[2 * G.dirsize + 1] = '\0';
+ inode->i_size = 2 * G.dirsize;
+ }
+ inode->i_mode = S_IFDIR + 0755;
+ inode->i_uid = GETUID;
+ if (inode->i_uid)
+ inode->i_gid = GETGID;
+ write_block(inode->i_zone[0], G.root_block);
+}
+
+#if ENABLE_FEATURE_MINIX2
+static void make_root_inode2(void)
+{
+ struct minix2_inode *inode = &INODE_BUF2[MINIX_ROOT_INO];
+
+ mark_inode(MINIX_ROOT_INO);
+ inode->i_zone[0] = get_free_block();
+ inode->i_nlinks = 2;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CUR_TIME;
+ if (G.badblocks)
+ inode->i_size = 3 * G.dirsize;
+ else {
+ G.root_block[2 * G.dirsize] = '\0';
+ G.root_block[2 * G.dirsize + 1] = '\0';
+ inode->i_size = 2 * G.dirsize;
+ }
+ inode->i_mode = S_IFDIR + 0755;
+ inode->i_uid = GETUID;
+ if (inode->i_uid)
+ inode->i_gid = GETGID;
+ write_block(inode->i_zone[0], G.root_block);
+}
+#else
+void make_root_inode2(void);
+#endif
+
+/*
+ * Perform a test of a block; return the number of
+ * blocks readable.
+ */
+static size_t do_check(char *buffer, size_t try, unsigned current_block)
+{
+ ssize_t got;
+
+ /* Seek to the correct loc. */
+ msg_eol = "seek failed during testing of blocks";
+ xlseek(dev_fd, current_block * BLOCK_SIZE, SEEK_SET);
+ msg_eol = "\n";
+
+ /* Try the read */
+ got = read(dev_fd, buffer, try * BLOCK_SIZE);
+ if (got < 0)
+ got = 0;
+ try = ((size_t)got) / BLOCK_SIZE;
+
+ if (got & (BLOCK_SIZE - 1))
+ fprintf(stderr, "Short read at block %u\n", (unsigned)(current_block + try));
+ return try;
+}
+
+static void alarm_intr(int alnum UNUSED_PARAM)
+{
+ if (G.currently_testing >= SB_ZONES)
+ return;
+ signal(SIGALRM, alarm_intr);
+ alarm(5);
+ if (!G.currently_testing)
+ return;
+ printf("%d ...", G.currently_testing);
+ fflush_all();
+}
+
+static void check_blocks(void)
+{
+ size_t try, got;
+
+ G.currently_testing = 0;
+ signal(SIGALRM, alarm_intr);
+ alarm(5);
+ while (G.currently_testing < SB_ZONES) {
+ msg_eol = "seek failed in check_blocks";
+ xlseek(dev_fd, G.currently_testing * BLOCK_SIZE, SEEK_SET);
+ msg_eol = "\n";
+ try = TEST_BUFFER_BLOCKS;
+ if (G.currently_testing + try > SB_ZONES)
+ try = SB_ZONES - G.currently_testing;
+ got = do_check(G.check_blocks_buffer, try, G.currently_testing);
+ G.currently_testing += got;
+ if (got == try)
+ continue;
+ if (G.currently_testing < SB_FIRSTZONE)
+ bb_error_msg_and_die("bad blocks before data-area: cannot make fs");
+ mark_zone(G.currently_testing);
+ G.badblocks++;
+ G.currently_testing++;
+ }
+ alarm(0);
+ printf("%d bad block(s)\n", G.badblocks);
+}
+
+static void get_list_blocks(char *filename)
+{
+ FILE *listfile;
+ unsigned long blockno;
+
+ listfile = xfopen_for_read(filename);
+ while (!feof(listfile)) {
+ fscanf(listfile, "%ld\n", &blockno);
+ mark_zone(blockno);
+ G.badblocks++;
+ }
+ printf("%d bad block(s)\n", G.badblocks);
+}
+
+static void setup_tables(void)
+{
+ unsigned long inodes;
+ unsigned norm_firstzone;
+ unsigned sb_zmaps;
+ unsigned i;
+
+ /* memset(G.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);
+}
+
+int mkfs_minix_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mkfs_minix_main(int argc UNUSED_PARAM, char **argv)
+{
+ unsigned opt;
+ char *tmp;
+ struct stat statbuf;
+ char *str_i;
+ char *listfile = NULL;
+
+ 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");
+#if ENABLE_FEATURE_MINIX2
+ if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
+ bb_error_msg_and_die("bad inode size");
+#endif
+
+ 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_and_die("not compiled with minix v2 support");
+#endif
+ }
+
+ G.device_name = *argv++;
+ if (!G.device_name)
+ bb_show_usage();
+ if (*argv)
+ G.total_blocks = xatou32(*argv);
+ else
+ G.total_blocks = get_size(G.device_name) / 1024;
+
+ if (G.total_blocks < 10)
+ bb_error_msg_and_die("must have at least 10 blocks");
+
+ if (version2) {
+ G.magic = MINIX2_SUPER_MAGIC2;
+ if (G.namelen == 14)
+ G.magic = MINIX2_SUPER_MAGIC;
+ } else if (G.total_blocks > 65535)
+ G.total_blocks = 65535;
+
+ /* Check if it is mounted */
+ if (find_mount_point(G.device_name, 0))
+ bb_error_msg_and_die("can't format mounted filesystem");
+
+ xmove_fd(xopen(G.device_name, O_RDWR), dev_fd);
+ xfstat(dev_fd, &statbuf, G.device_name);
+ if (!S_ISBLK(statbuf.st_mode))
+ opt &= ~1; // clear -c (check)
+
+/* I don't know why someone has special code to prevent mkfs.minix
+ * on IDE devices. Why IDE but not SCSI, etc?... */
+#if 0
+ else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
+ /* what is this? */
+ bb_error_msg_and_die("will not try "
+ "to make filesystem on '%s'", G.device_name);
+#endif
+
+ tmp = G.root_block;
+ *(short *) tmp = 1;
+ strcpy(tmp + 2, ".");
+ tmp += G.dirsize;
+ *(short *) tmp = 1;
+ strcpy(tmp + 2, "..");
+ tmp += G.dirsize;
+ *(short *) tmp = 2;
+ strcpy(tmp + 2, ".badblocks");
+
+ setup_tables();
+
+ if (opt & 1) // -c ?
+ check_blocks();
+ else if (listfile)
+ get_list_blocks(listfile);
+
+ if (version2) {
+ make_root_inode2();
+ make_bad_inode2();
+ } else {
+ make_root_inode();
+ make_bad_inode();
+ }
+
+ mark_good_blocks();
+ write_tables();
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/mkfs_reiser.c b/ap/app/busybox/src/util-linux/mkfs_reiser.c
new file mode 100644
index 0000000..b4efb9e
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/mkfs_reiser.c
@@ -0,0 +1,375 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mkfs_reiser: utility to create ReiserFS filesystem
+ *
+ * Busybox'ed (2009) by Vladimir Dronnikov <dronnikov@gmail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//usage:#define mkfs_reiser_trivial_usage
+//usage: "[-f] [-l LABEL] BLOCKDEV [4K-BLOCKS]"
+//usage:#define mkfs_reiser_full_usage "\n\n"
+//usage: "Make a ReiserFS V3 filesystem\n"
+//usage: "\n -f Force"
+//usage: "\n -l LBL Volume label"
+
+#include "libbb.h"
+#include <linux/fs.h>
+
+char BUG_wrong_field_size(void);
+#define STORE_LE(field, value) \
+do { \
+ if (sizeof(field) == 4) \
+ field = SWAP_LE32(value); \
+ else if (sizeof(field) == 2) \
+ field = SWAP_LE16(value); \
+ else if (sizeof(field) == 1) \
+ field = (value); \
+ else \
+ BUG_wrong_field_size(); \
+} while (0)
+
+#define FETCH_LE32(field) \
+ (sizeof(field) == 4 ? SWAP_LE32(field) : BUG_wrong_field_size())
+
+struct journal_params {
+ uint32_t jp_journal_1st_block; /* where does journal start from on its device */
+ uint32_t jp_journal_dev; /* journal device st_rdev */
+ uint32_t jp_journal_size; /* size of the journal on FS creation. used to make sure they don't overflow it */
+ uint32_t jp_journal_trans_max; /* max number of blocks in a transaction. */
+ uint32_t jp_journal_magic; /* random value made on fs creation (this was sb_journal_block_count) */
+ uint32_t jp_journal_max_batch; /* max number of blocks to batch into a trans */
+ uint32_t jp_journal_max_commit_age; /* in seconds, how old can an async commit be */
+ uint32_t jp_journal_max_trans_age; /* in seconds, how old can a transaction be */
+};
+
+struct reiserfs_journal_header {
+ uint32_t jh_last_flush_trans_id; /* id of last fully flushed transaction */
+ uint32_t jh_first_unflushed_offset; /* offset in the log of where to start replay after a crash */
+ uint32_t jh_mount_id;
+ struct journal_params jh_journal;
+ uint32_t jh_last_check_mount_id; /* the mount id of the fs during the last reiserfsck --check. */
+};
+
+struct reiserfs_super_block {
+ uint32_t sb_block_count; /* 0 number of block on data device */
+ uint32_t sb_free_blocks; /* 4 free blocks count */
+ uint32_t sb_root_block; /* 8 root of the tree */
+
+ struct journal_params sb_journal; /* 12 */
+
+ uint16_t sb_blocksize; /* 44 */
+ uint16_t sb_oid_maxsize; /* 46 max size of object id array, see get_objectid() commentary */
+ uint16_t sb_oid_cursize; /* 48 current size of object id array */
+ uint16_t sb_umount_state; /* 50 this is set to 1 when filesystem was umounted, to 2 - when not */
+
+ char s_magic[10]; /* 52 "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */
+ uint16_t sb_fs_state; /* 62 it is set to used by fsck to mark which phase of rebuilding is done (used for fsck debugging) */
+ uint32_t sb_hash_function_code; /* 64 code of fuction which was/is/will be used to sort names in a directory. See codes in above */
+ uint16_t sb_tree_height; /* 68 height of filesytem tree. Tree consisting of only one root block has 2 here */
+ uint16_t sb_bmap_nr; /* 70 amount of bitmap blocks needed to address each block of file system */
+ uint16_t sb_version; /* 72 this field is only reliable on filesystem with non-standard journal */
+ uint16_t sb_reserved_for_journal; /* 74 size in blocks of journal area on main device, we need to keep after non-standard journal relocation */
+ uint32_t sb_inode_generation; /* 76 */
+ uint32_t sb_flags; /* 80 Right now used only by inode-attributes, if enabled */
+ unsigned char s_uuid[16]; /* 84 filesystem unique identifier */
+ unsigned char s_label[16]; /* 100 filesystem volume label */
+ uint16_t sb_mnt_count; /* 116 */
+ uint16_t sb_max_mnt_count; /* 118 */
+ uint32_t sb_lastcheck; /* 120 */
+ uint32_t sb_check_interval; /* 124 */
+/* zero filled by mkreiserfs and reiserfs_convert_objectid_map_v1() so any additions must be updated there as well. */
+ char s_unused[76]; /* 128 */
+ /* 204 */
+};
+
+/* Header of a disk block. More precisely, header of a formatted leaf
+ or internal node, and not the header of an unformatted node. */
+struct block_head {
+ uint16_t blk2_level; /* Level of a block in the tree. */
+ uint16_t blk2_nr_item; /* Number of keys/items in a block. */
+ uint16_t blk2_free_space; /* Block free space in bytes. */
+ uint16_t blk_reserved;
+ uint32_t reserved[4];
+};
+
+#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
+
+#define REISERFS_3_6_SUPER_MAGIC_STRING "ReIsEr2Fs"
+#define REISERFS_FORMAT_3_6 2
+#define DEFAULT_MAX_MNT_COUNT 30 /* 30 mounts */
+#define DEFAULT_CHECK_INTERVAL (180 * 60 * 60 * 24) /* 180 days */
+
+#define FS_CLEANLY_UMOUNTED 1 /* this was REISERFS_VALID_FS */
+
+#define JOURNAL_MIN_SIZE 512
+/* biggest possible single transaction, don't change for now (8/3/99) */
+#define JOURNAL_TRANS_MAX 1024
+#define JOURNAL_TRANS_MIN 256 /* need to check whether it works */
+#define JOURNAL_DEFAULT_RATIO 8 /* default journal size / max trans length */
+#define JOURNAL_MIN_RATIO 2
+/* max blocks to batch into one transaction, don't make this any bigger than 900 */
+#define JOURNAL_MAX_BATCH 900
+#define JOURNAL_MAX_COMMIT_AGE 30
+
+
+// Standard mkreiserfs 3.6.21:
+// -b | --block-size N size of file-system block, in bytes
+// -j | --journal-device FILE path to separate device to hold journal
+// -s | --journal-size N size of the journal in blocks
+// -o | --journal-offset N offset of the journal from the start of
+// the separate device, in blocks
+// -t | --transaction-max-size N maximal size of transaction, in blocks
+// -B | --badblocks file store all bad blocks given in file on the fs
+// -h | --hash rupasov|tea|r5 hash function to use by default
+// -u | --uuid UUID store UUID in the superblock
+// -l | --label LABEL store LABEL in the superblock
+// --format 3.5|3.6 old 3.5 format or newer 3.6
+// -f | --force specified once, make mkreiserfs the whole
+// disk, not block device or mounted partition;
+// specified twice, do not ask for confirmation
+// -q | --quiet quiet work without messages, progress and
+// questions. Useful if run in a script. For use
+// by end users only.
+// -d | --debug print debugging information during mkreiser
+// -V print version and exit
+
+// Options not commented below are taken but silently ignored:
+enum {
+ OPT_b = 1 << 0,
+ OPT_j = 1 << 1,
+ OPT_s = 1 << 2,
+ OPT_o = 1 << 3,
+ OPT_t = 1 << 4,
+ OPT_B = 1 << 5,
+ OPT_h = 1 << 6,
+ OPT_u = 1 << 7,
+ OPT_l = 1 << 8, // label
+ OPT_f = 1 << 9, // ask no questions
+ OPT_q = 1 << 10,
+ OPT_d = 1 << 11,
+ //OPT_V = 1 << 12, // -V version. bbox applets don't support that
+};
+
+int mkfs_reiser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mkfs_reiser_main(int argc UNUSED_PARAM, char **argv)
+{
+ unsigned blocksize = 4096;
+ unsigned journal_blocks = 8192;
+ unsigned blocks, bitmap_blocks, i, block;
+ time_t timestamp;
+ const char *label = "";
+ struct stat st;
+ int fd;
+ uint8_t *buf;
+ struct reiserfs_super_block *sb;
+ struct journal_params *jp;
+ struct block_head *root;
+
+ // using global "option_mask32" instead of local "opts":
+ // we are register starved here
+ opt_complementary = "-1:b+";
+ /*opts =*/ getopt32(argv, "b:j:s:o:t:B:h:u:l:fqd",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &label);
+ argv += optind; // argv[0] -- device
+
+ // check the device is a block device
+ fd = xopen(argv[0], O_WRONLY | O_EXCL);
+ xfstat(fd, &st, argv[0]);
+ if (!S_ISBLK(st.st_mode) && !(option_mask32 & OPT_f))
+ bb_error_msg_and_die("%s: not a block device", argv[0]);
+
+ // check if it is mounted
+ // N.B. what if we format a file? find_mount_point will return false negative since
+ // it is loop block device which is mounted!
+ if (find_mount_point(argv[0], 0))
+ bb_error_msg_and_die("can't format mounted filesystem");
+
+ // open the device, get size in blocks
+ blocks = get_volume_size_in_bytes(fd, argv[1], blocksize, /*extend:*/ 1) / blocksize;
+
+ // block number sanity check
+ // we have a limit: skipped area, super block, journal and root block
+ // all have to be addressed by one first bitmap
+ block = REISERFS_DISK_OFFSET_IN_BYTES / blocksize // boot area
+ + 1 // sb
+ + 1 // bitmap#0
+ + journal_blocks+1 // journal
+ ;
+
+ // count overhead
+ bitmap_blocks = (blocks - 1) / (blocksize * 8) + 1;
+ i = block + bitmap_blocks;
+
+ // check overhead
+ if (MIN(blocksize * 8, blocks) < i)
+ bb_error_msg_and_die("need >= %u blocks", i);
+
+ // ask confirmation?
+ // TODO: ???
+
+ // wipe out first REISERFS_DISK_OFFSET_IN_BYTES of device
+ // TODO: do we really need to wipe?!
+ xlseek(fd, REISERFS_DISK_OFFSET_IN_BYTES, SEEK_SET);
+
+ // fill superblock
+ sb = (struct reiserfs_super_block *)xzalloc(blocksize);
+ // block count
+ STORE_LE(sb->sb_block_count, blocks);
+ STORE_LE(sb->sb_free_blocks, blocks - i);
+ // TODO: decypher!
+ STORE_LE(sb->sb_root_block, block);
+ // fill journal related fields
+ jp = &sb->sb_journal;
+ STORE_LE(jp->jp_journal_1st_block, REISERFS_DISK_OFFSET_IN_BYTES / blocksize + 1/*sb*/ + 1/*bmp#0*/);
+ timestamp = time(NULL);
+ srandom(timestamp);
+ STORE_LE(jp->jp_journal_magic, random());
+ STORE_LE(jp->jp_journal_size, journal_blocks);
+ STORE_LE(jp->jp_journal_trans_max, JOURNAL_TRANS_MAX);
+ STORE_LE(jp->jp_journal_max_batch, JOURNAL_MAX_BATCH);
+ STORE_LE(jp->jp_journal_max_commit_age, JOURNAL_MAX_COMMIT_AGE);
+ // sizes
+ STORE_LE(sb->sb_blocksize, blocksize);
+ STORE_LE(sb->sb_oid_maxsize, (blocksize - sizeof(*sb)) / sizeof(uint32_t) / 2 * 2);
+ STORE_LE(sb->sb_oid_cursize, 2); // "." and ".."
+ strcpy(sb->s_magic, REISERFS_3_6_SUPER_MAGIC_STRING);
+ STORE_LE(sb->sb_bmap_nr, (bitmap_blocks > ((1LL << 16) - 1)) ? 0 : bitmap_blocks);
+ // misc
+ STORE_LE(sb->sb_version, REISERFS_FORMAT_3_6);
+ STORE_LE(sb->sb_lastcheck, timestamp);
+ STORE_LE(sb->sb_check_interval, DEFAULT_CHECK_INTERVAL);
+ STORE_LE(sb->sb_mnt_count, 1);
+ STORE_LE(sb->sb_max_mnt_count, DEFAULT_MAX_MNT_COUNT);
+ STORE_LE(sb->sb_umount_state, FS_CLEANLY_UMOUNTED);
+ STORE_LE(sb->sb_tree_height, 2);
+ STORE_LE(sb->sb_hash_function_code, 3); // R5_HASH
+ STORE_LE(sb->sb_flags, 1);
+ //STORE_LE(sb->sb_reserved_for_journal, 0);
+ // create UUID
+ generate_uuid(sb->s_uuid);
+ // write the label
+ safe_strncpy((char *)sb->s_label, label, sizeof(sb->s_label));
+
+ // TODO: EMPIRIC! ENDIANNESS!
+ // superblock has only 204 bytes. What are these?
+ buf = (uint8_t *)sb;
+ buf[205] = 1;
+ buf[209] = 3;
+
+ // put superblock
+ xwrite(fd, sb, blocksize);
+
+ // create bitmaps
+ buf = xzalloc(blocksize);
+
+ // bitmap #0 uses initial "block"+1 blocks
+ i = block + 1;
+ memset(buf, 0xFF, i / 8);
+ buf[i / 8] = (1 << (i & 7)) - 1; //0..7 => 00000000..01111111
+ // mark trailing absent blocks, if any
+ if (blocks < 8*blocksize) {
+ unsigned n = 8*blocksize - blocks;
+ i = n / 8;
+ buf[blocksize - i - 1] |= 0x7F00 >> (n & 7); //0..7 => 00000000..11111110
+ memset(buf + blocksize - i, 0xFF, i); // N.B. no overflow here!
+ }
+ // put bitmap #0
+ xwrite(fd, buf, blocksize);
+
+ // now go journal blocks
+ memset(buf, 0, blocksize);
+ for (i = 0; i < journal_blocks; i++)
+ xwrite(fd, buf, blocksize);
+ // dump journal control block
+ memcpy(&((struct reiserfs_journal_header *)buf)->jh_journal, &sb->sb_journal, sizeof(sb->sb_journal));
+ xwrite(fd, buf, blocksize);
+
+ // other bitmaps are in every (8*blocksize)-th block
+ // N.B. they use the only block -- namely bitmap itself!
+ buf[0] = 0x01;
+ // put bitmaps
+ for (i = 1; i < bitmap_blocks; i++) {
+ xlseek(fd, i*8*blocksize * blocksize, SEEK_SET);
+ // mark trailing absent blocks, if any
+ if (i == bitmap_blocks - 1 && (blocks % (8*blocksize))) {
+ unsigned n = 8*blocksize - blocks % (8*blocksize);
+ unsigned j = n / 8;
+ buf[blocksize - j - 1] |= 0x7F00 >> (n & 7); //0..7 => 00000000..11111110
+ memset(buf + blocksize - j, 0xFF, j); // N.B. no overflow here!
+ }
+ xwrite(fd, buf, blocksize);
+ }
+
+ // fill root block
+ // block head
+ memset(buf, 0, blocksize);
+ root = (struct block_head *)buf;
+ STORE_LE(root->blk2_level, 1); // leaf node
+ STORE_LE(root->blk2_nr_item, 2); // "." and ".."
+ STORE_LE(root->blk2_free_space, blocksize - sizeof(struct block_head));
+ // item head
+ // root directory
+ // TODO: EMPIRIC! ENDIANNESS!
+ // TODO: indented assignments seem to be timestamps
+buf[4] = 0134;
+buf[24] = 01;
+buf[28] = 02;
+buf[42] = 054;
+buf[44] = 0324;
+buf[45] = 017;
+buf[46] = 01;
+buf[48] = 01;
+buf[52] = 02;
+buf[56] = 01;
+buf[60] = 0364;
+buf[61] = 01;
+buf[64] = 02;
+buf[66] = 060;
+buf[68] = 0244;
+buf[69] = 017;
+buf[4004] = 01;
+buf[4008] = 01;
+buf[4012] = 02;
+buf[4016] = 050;
+buf[4018] = 04;
+buf[4020] = 02;
+buf[4028] = 01;
+buf[4032] = 040;
+buf[4034] = 04;
+
+buf[4036] = 056; buf[4037] = 056; // ".."
+buf[4044] = 056; // "."
+
+buf[4052] = 0355;
+buf[4053] = 0101;
+buf[4056] = 03;
+buf[4060] = 060;
+ buf[4076] = 0173;
+ buf[4077] = 0240;
+ buf[4078] = 0344;
+ buf[4079] = 0112;
+ buf[4080] = 0173;
+ buf[4081] = 0240;
+ buf[4082] = 0344;
+ buf[4083] = 0112;
+ buf[4084] = 0173;
+ buf[4085] = 0240;
+ buf[4086] = 0344;
+ buf[4087] = 0112;
+buf[4088] = 01;
+
+ // put root block
+ xlseek(fd, block * blocksize, SEEK_SET);
+ xwrite(fd, buf, blocksize);
+
+ // cleanup
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(buf);
+ free(sb);
+ }
+
+ xclose(fd);
+ return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/util-linux/mkfs_vfat.c b/ap/app/busybox/src/util-linux/mkfs_vfat.c
new file mode 100644
index 0000000..7d81ed0
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/mkfs_vfat.c
@@ -0,0 +1,630 @@
+/* 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 source tree.
+ */
+
+//usage:#define mkfs_vfat_trivial_usage
+//usage: "[-v] [-n LABEL] BLOCKDEV [KBYTES]"
+/* Accepted but ignored:
+ "[-c] [-C] [-I] [-l bad-block-file] [-b backup-boot-sector] "
+ "[-m boot-msg-file] [-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] "
+*/
+//usage:#define mkfs_vfat_full_usage "\n\n"
+//usage: "Make a FAT32 filesystem\n"
+/* //usage: "\n -c Check device for bad blocks" */
+//usage: "\n -v Verbose"
+/* //usage: "\n -I Allow to use entire disk device (e.g. /dev/hda)" */
+//usage: "\n -n LBL Volume label"
+
+#include "libbb.h"
+
+#include <linux/hdreg.h> /* HDIO_GETGEO */
+#include <linux/fd.h> /* FDGETPRM */
+#include <sys/mount.h> /* BLKSSZGET */
+#if !defined(BLKSSZGET)
+# define BLKSSZGET _IO(0x12, 104)
+#endif
+//#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 */
+} 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" */
+} PACKED; /* 05a end. Total size 26 (0x1a) bytes */
+
+struct msdos_boot_sector {
+ /* We use strcpy to fill both, and gcc-4.4.x complains if they are separate */
+ char boot_jump_and_sys_id[3+8]; /* 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 */
+} 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 */
+} 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] = SWAP_LE32(value)
+
+void BUG_unsupported_field_size(void);
+#define STORE_LE(field, value) \
+do { \
+ if (sizeof(field) == 4) \
+ field = SWAP_LE32(value); \
+ else if (sizeof(field) == 2) \
+ field = SWAP_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_RDWR);
+ xfstat(dev, &st, device_name);
+
+ //
+ // Get image size and sector size
+ //
+ bytes_per_sect = SECTOR_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;
+#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, 0))
+ 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);
+ }
+ }
+ volume_size_bytes = get_volume_size_in_bytes(dev, argv[1], 1024, /*extend:*/ 1);
+ 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, ¶m);
+ 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;
+ uoff_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 > 0x80ffffff)
+ goto next;
+ total_clust = tcl; // fits in uint32_t
+ // Every cluster needs 4 bytes in FAT. +2 entries since
+ // FAT has space for non-existent clusters 0 and 1.
+ // Let's see how many sectors that needs.
+ //May overflow at "*4":
+ //spf_adj = ((total_clust+2) * 4 + bytes_per_sect-1) / bytes_per_sect - sect_per_fat;
+ //Same in the more obscure, non-overflowing form:
+ spf_adj = ((total_clust+2) + (bytes_per_sect/4)-1) / (bytes_per_sect/4) - 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_and_sys_id, "\xeb\x58\x90" "mkdosfs");
+ STORE_LE(boot_blk->bytes_per_sect, bytes_per_sect);
+ STORE_LE(boot_blk->sect_per_clust, sect_per_clust);
+ // cast in needed on big endian to suppress a warning
+ STORE_LE(boot_blk->reserved_sect, (uint16_t)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_time;
+ 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_time);
+ t = (tm_time.tm_sec >> 1) + (tm_time.tm_min << 5) + (tm_time.tm_hour << 11);
+ d = tm_time.tm_mday + ((tm_time.tm_mon+1) << 5) + ((tm_time.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/ap/app/busybox/src/util-linux/mkswap.c b/ap/app/busybox/src/util-linux/mkswap.c
new file mode 100644
index 0000000..b5d2c49
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/mkswap.c
@@ -0,0 +1,149 @@
+/* vi: set sw=4 ts=4: */
+/* mkswap.c - format swap device (Linux v1 only)
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//usage:#define mkswap_trivial_usage
+//usage: "[-L LBL] BLOCKDEV [KBYTES]"
+//usage:#define mkswap_full_usage "\n\n"
+//usage: "Prepare BLOCKDEV to be used as swap partition\n"
+//usage: "\n -L LBL Label"
+
+#include "libbb.h"
+
+#if ENABLE_SELINUX
+static void mkswap_selinux_setcontext(int fd, const char *path)
+{
+ struct stat stbuf;
+
+ if (!is_selinux_enabled())
+ return;
+
+ xfstat(fd, &stbuf, path);
+ 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;
+ }
+ 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);
+ }
+ }
+ return;
+ error:
+ bb_perror_msg_and_die("SELinux relabeling failed");
+}
+#else
+# define mkswap_selinux_setcontext(fd, path) ((void)0)
+#endif
+
+/* from Linux 2.6.23 */
+/*
+ * Magic header for a swap area. ... Note that the first
+ * kilobyte is reserved for boot loader or disk label stuff.
+ */
+struct swap_header_v1 {
+/* char bootbits[1024]; Space for disklabel etc. */
+ uint32_t version; /* second kbyte, word 0 */
+ uint32_t last_page; /* 1 */
+ uint32_t nr_badpages; /* 2 */
+ char sws_uuid[16]; /* 3,4,5,6 */
+ char sws_volume[16]; /* 7,8,9,10 */
+ uint32_t padding[117]; /* 11..127 */
+ uint32_t badpages[1]; /* 128 */
+ /* total 129 32-bit words in 2nd kilobyte */
+} FIX_ALIASING;
+
+#define NWORDS 129
+#define hdr ((struct swap_header_v1*)bb_common_bufsiz1)
+
+struct BUG_sizes {
+ char swap_header_v1_wrong[sizeof(*hdr) != (NWORDS * 4) ? -1 : 1];
+ char bufsiz1_is_too_small[COMMON_BUFSIZE < (NWORDS * 4) ? -1 : 1];
+};
+
+/* 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 UNUSED_PARAM, char **argv)
+{
+ int fd;
+ unsigned pagesize;
+ off_t len;
+ const char *label = "";
+
+ opt_complementary = "-1"; /* at least one param */
+ /* TODO: -p PAGESZ, -U UUID */
+ getopt32(argv, "L:", &label);
+ argv += optind;
+
+ fd = xopen(argv[0], O_WRONLY);
+
+ /* Figure out how big the device is */
+ len = get_volume_size_in_bytes(fd, argv[1], 1024, /*extend:*/ 1);
+ pagesize = getpagesize();
+ len -= pagesize;
+
+ /* Announce our intentions */
+ printf("Setting up swapspace version 1, size = %"OFF_FMT"u bytes\n", len);
+ mkswap_selinux_setcontext(fd, argv[0]);
+
+ /* hdr is zero-filled so far. Clear the first kbyte, or else
+ * mkswap-ing former FAT partition does NOT erase its signature.
+ *
+ * util-linux-ng 2.17.2 claims to erase it only if it does not see
+ * a partition table and is not run on whole disk. -f forces it.
+ */
+ xwrite(fd, hdr, 1024);
+
+ /* Fill the header. */
+ hdr->version = 1;
+ hdr->last_page = (uoff_t)len / pagesize;
+
+ if (ENABLE_FEATURE_MKSWAP_UUID) {
+ char uuid_string[32];
+ generate_uuid((void*)hdr->sws_uuid);
+ bin2hex(uuid_string, hdr->sws_uuid, 16);
+ /* f.e. UUID=dfd9c173-be52-4d27-99a5-c34c6c2ff55f */
+ printf("UUID=%.8s" "-%.4s-%.4s-%.4s-%.12s\n",
+ uuid_string,
+ uuid_string+8,
+ uuid_string+8+4,
+ uuid_string+8+4+4,
+ uuid_string+8+4+4+4
+ );
+ }
+ safe_strncpy(hdr->sws_volume, label, 16);
+
+ /* Write the header. Sync to disk because some kernel versions check
+ * signature on disk (not in cache) during swapon. */
+ xwrite(fd, hdr, NWORDS * 4);
+ xlseek(fd, pagesize - 10, SEEK_SET);
+ xwrite(fd, SWAPSPACE2, 10);
+ fsync(fd);
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(fd);
+
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/more.c b/ap/app/busybox/src/util-linux/more.c
new file mode 100644
index 0000000..3595713
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/more.c
@@ -0,0 +1,212 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini more implementation for busybox
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Latest version blended together by Erik Andersen <andersen@codepoet.org>,
+ * based on the original more implementation by Bruce, and code from the
+ * Debian boot-floppies team.
+ *
+ * Termios corrects by Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+//usage:#define more_trivial_usage
+//usage: "[FILE]..."
+//usage:#define more_full_usage "\n\n"
+//usage: "View FILE (or stdin) one screenful at a time"
+//usage:
+//usage:#define more_example_usage
+//usage: "$ dmesg | more\n"
+
+#include "libbb.h"
+
+/* Support for FEATURE_USE_TERMIOS */
+
+struct globals {
+ int cin_fileno;
+ struct termios initial_settings;
+ struct termios new_settings;
+} FIX_ALIASING;
+#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 )
+
+#define setTermSettings(fd, argp) \
+do { \
+ if (ENABLE_FEATURE_USE_TERMIOS) \
+ tcsetattr(fd, TCSANOW, argp); \
+} while (0)
+#define getTermSettings(fd, argp) tcgetattr(fd, argp)
+
+static void gotsig(int sig UNUSED_PARAM)
+{
+ /* bb_putchar_stderr doesn't use stdio buffering,
+ * therefore it is safe in signal handler */
+ bb_putchar_stderr('\n');
+ setTermSettings(cin_fileno, &initial_settings);
+ _exit(EXIT_FAILURE);
+}
+
+#define CONVERTED_TAB_SIZE 8
+
+int more_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int more_main(int argc UNUSED_PARAM, char **argv)
+{
+ int c = c; /* for compiler */
+ int lines;
+ int input = 0;
+ int spaces = 0;
+ int please_display_more_prompt;
+ struct stat st;
+ FILE *file;
+ FILE *cin;
+ int len;
+ unsigned terminal_width;
+ unsigned terminal_height;
+
+ INIT_G();
+
+ argv++;
+ /* Another popular pager, most, detects when stdout
+ * is not a tty and turns into cat. This makes sense. */
+ if (!isatty(STDOUT_FILENO))
+ return bb_cat(argv);
+ cin = fopen_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 | 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);
+ }
+
+ do {
+ file = stdin;
+ if (*argv) {
+ file = fopen_or_warn(*argv, "r");
+ if (!file)
+ continue;
+ }
+ st.st_size = 0;
+ fstat(fileno(file), &st);
+
+ please_display_more_prompt = 0;
+ /* never returns w, h <= 1 */
+ get_terminal_width_height(fileno(cin), &terminal_width, &terminal_height);
+ terminal_height -= 1;
+
+ len = 0;
+ lines = 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 (st.st_size != 0) {
+ uoff_t d = (uoff_t)st.st_size / 100;
+ if (d == 0)
+ d = 1;
+ len += printf("(%u%% of %"OFF_FMT"u bytes)",
+ (int) ((uoff_t)ftello(file) / d),
+ st.st_size);
+ }
+ fflush_all();
+
+ /*
+ * We've just displayed the "--More--" prompt, so now we need
+ * to get input from the user.
+ */
+ for (;;) {
+ input = getc(cin);
+ input = tolower(input);
+ if (!ENABLE_FEATURE_USE_TERMIOS)
+ printf("\033[A"); /* cursor up */
+ /* 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;
+ 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;
+ }
+ }
+
+ /* Crudely convert tabs into spaces, which are
+ * a bajillion times easier to deal with. */
+ if (c == '\t') {
+ spaces = ((unsigned)~len) % CONVERTED_TAB_SIZE;
+ 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
+ *
+ * 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.
+ */
+ 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;
+ }
+ 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);
+ die_if_ferror_stdout(); /* if tty was destroyed (closed xterm, etc) */
+ }
+ fclose(file);
+ fflush_all();
+ } while (*argv && *++argv);
+ end:
+ setTermSettings(cin_fileno, &initial_settings);
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/mount.c b/ap/app/busybox/src/util-linux/mount.c
new file mode 100644
index 0000000..2f94b69
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/mount.c
@@ -0,0 +1,2305 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini mount implementation for busybox
+ *
+ * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2005-2006 by Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+// 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.
+//
+
+//usage:#define mount_trivial_usage
+//usage: "[OPTIONS] [-o OPTS] DEVICE NODE"
+//usage:#define mount_full_usage "\n\n"
+//usage: "Mount a filesystem. Filesystem autodetection requires /proc.\n"
+//usage: "\n -a Mount all filesystems in fstab"
+//usage: IF_FEATURE_MOUNT_FAKE(
+//usage: IF_FEATURE_MTAB_SUPPORT(
+//usage: "\n -f Update /etc/mtab, but don't mount"
+//usage: )
+//usage: IF_NOT_FEATURE_MTAB_SUPPORT(
+//usage: "\n -f Dry run"
+//usage: )
+//usage: )
+//usage: IF_FEATURE_MOUNT_HELPERS(
+//usage: "\n -i Don't run mount helper"
+//usage: )
+//usage: IF_FEATURE_MTAB_SUPPORT(
+//usage: "\n -n Don't update /etc/mtab"
+//usage: )
+//usage: IF_FEATURE_MOUNT_VERBOSE(
+//usage: "\n -v Verbose"
+//usage: )
+////usage: "\n -s Sloppy (ignored)"
+//usage: "\n -r Read-only mount"
+//usage: "\n -w Read-write mount (default)"
+//usage: "\n -t FSTYPE[,...] Filesystem type(s)"
+//usage: "\n -O OPT Mount only filesystems with option OPT (-a only)"
+//usage: "\n-o OPT:"
+//usage: IF_FEATURE_MOUNT_LOOP(
+//usage: "\n loop Ignored (loop devices are autodetected)"
+//usage: )
+//usage: IF_FEATURE_MOUNT_FLAGS(
+//usage: "\n [a]sync Writes are [a]synchronous"
+//usage: "\n [no]atime Disable/enable updates to inode access times"
+//usage: "\n [no]diratime Disable/enable atime updates to directories"
+//usage: "\n [no]relatime Disable/enable atime updates relative to modification time"
+//usage: "\n [no]dev (Dis)allow use of special device files"
+//usage: "\n [no]exec (Dis)allow use of executable files"
+//usage: "\n [no]suid (Dis)allow set-user-id-root programs"
+//usage: "\n [r]shared Convert [recursively] to a shared subtree"
+//usage: "\n [r]slave Convert [recursively] to a slave subtree"
+//usage: "\n [r]private Convert [recursively] to a private subtree"
+//usage: "\n [un]bindable Make mount point [un]able to be bind mounted"
+//usage: "\n [r]bind Bind a file or directory [recursively] to another location"
+//usage: "\n move Relocate an existing mount point"
+//usage: )
+//usage: "\n remount Remount a mounted filesystem, changing flags"
+//usage: "\n ro/rw Same as -r/-w"
+//usage: "\n"
+//usage: "\nThere are filesystem-specific -o flags."
+//usage:
+//usage:#define mount_example_usage
+//usage: "$ mount\n"
+//usage: "/dev/hda3 on / type minix (rw)\n"
+//usage: "proc on /proc type proc (rw)\n"
+//usage: "devpts on /dev/pts type devpts (rw)\n"
+//usage: "$ mount /dev/fd0 /mnt -t msdos -o ro\n"
+//usage: "$ mount /tmp/diskimage /opt -t ext2 -o loop\n"
+//usage: "$ mount cd_image.iso mydir\n"
+//usage:#define mount_notes_usage
+//usage: "Returns 0 for success, number of failed mounts for -a, or errno for one mount."
+
+#include <mntent.h>
+#include <syslog.h>
+#include <sys/mount.h>
+// Grab more as needed from util-linux's mount/mount_constants.h
+#ifndef MS_DIRSYNC
+# define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous
+#endif
+#ifndef MS_UNION
+# define MS_UNION (1 << 8)
+#endif
+#ifndef MS_BIND
+# define MS_BIND (1 << 12)
+#endif
+#ifndef MS_MOVE
+# define MS_MOVE (1 << 13)
+#endif
+#ifndef MS_RECURSIVE
+# define MS_RECURSIVE (1 << 14)
+#endif
+#ifndef MS_SILENT
+# define MS_SILENT (1 << 15)
+#endif
+// The shared subtree stuff, which went in around 2.6.15
+#ifndef MS_UNBINDABLE
+# define MS_UNBINDABLE (1 << 17)
+#endif
+#ifndef MS_PRIVATE
+# define MS_PRIVATE (1 << 18)
+#endif
+#ifndef MS_SLAVE
+# define MS_SLAVE (1 << 19)
+#endif
+#ifndef MS_SHARED
+# define MS_SHARED (1 << 20)
+#endif
+#ifndef MS_RELATIME
+# define MS_RELATIME (1 << 21)
+#endif
+#ifndef MS_STRICTATIME
+# define MS_STRICTATIME (1 << 24)
+#endif
+
+/* Any ~MS_FOO value has this bit set: */
+#define BB_MS_INVERTED_VALUE (1u << 31)
+
+#include "libbb.h"
+#if ENABLE_FEATURE_MOUNT_LABEL
+# include "volume_id.h"
+#else
+# define resolve_mount_spec(fsname) ((void)0)
+#endif
+
+// Needed for nfs support only
+#include <sys/utsname.h>
+#undef TRUE
+#undef FALSE
+#if ENABLE_FEATURE_MOUNT_NFS
+/* 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
+# include <rpc/rpc.h>
+# include <rpc/pmap_prot.h>
+# include <rpc/pmap_clnt.h>
+#endif
+#ifndef MS_RELATIME
+#define MS_RELATIME (1 << 21) /* Update atime relative to mtime/ctime */
+#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 {
+ MOUNT_USERS = (1 << 28) * ENABLE_DESKTOP,
+ MOUNT_NOAUTO = (1 << 29),
+ MOUNT_SWAP = (1 << 30),
+};
+
+
+#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 USE_MTAB (!(option_mask32 & OPT_n))
+#else
+#define USE_MTAB 0
+#endif
+
+#if ENABLE_FEATURE_MOUNT_FAKE
+#define FAKE_IT (option_mask32 & OPT_f)
+#else
+#define FAKE_IT 0
+#endif
+
+#if ENABLE_FEATURE_MOUNT_HELPERS
+#define HELPERS_ALLOWED (!(option_mask32 & OPT_i))
+#else
+#define HELPERS_ALLOWED 0
+#endif
+
+
+// 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.
+
+ IF_FEATURE_MOUNT_LOOP(
+ /* "loop" */ 0,
+ )
+
+ IF_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,
+ IF_DESKTOP(/* "user" */ MOUNT_USERS,)
+ IF_DESKTOP(/* "users" */ MOUNT_USERS,)
+ /* "_netdev" */ 0,
+ IF_DESKTOP(/* "comment=" */ 0,) /* systemd uses this in fstab */
+ )
+
+ IF_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,
+ /* "strictatime" */ MS_STRICTATIME,
+ /* "loud" */ ~MS_SILENT,
+ /* "rbind" */ MS_BIND|MS_RECURSIVE,
+
+ // action flags
+ /* "union" */ MS_UNION,
+ /* "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_PRIVATE|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 char mount_option_str[] =
+ IF_FEATURE_MOUNT_LOOP(
+ "loop\0"
+ )
+ IF_FEATURE_MOUNT_FSTAB(
+ "defaults\0"
+ // "quiet\0" - do not filter out, vfat wants to see it
+ "noauto\0"
+ "sw\0"
+ "swap\0"
+ IF_DESKTOP("user\0")
+ IF_DESKTOP("users\0")
+ "_netdev\0"
+ IF_DESKTOP("comment=\0") /* systemd uses this in fstab */
+ )
+ IF_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"
+ "strictatime\0"
+ "loud\0"
+ "rbind\0"
+
+ // action flags
+ "union\0"
+ "bind\0"
+ "move\0"
+ "make-shared\0"
+ "make-slave\0"
+ "make-private\0"
+ "make-unbindable\0"
+ "make-rshared\0"
+ "make-rslave\0"
+ "make-rprivate\0"
+ "make-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];
+} FIX_ALIASING;
+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 )
+#define INIT_G() do { } while (0)
+
+#if ENABLE_FEATURE_MTAB_SUPPORT
+/*
+ * update_mtab_entry_on_move() is used to update entry in case of mount --move.
+ * we are looking for existing entries mnt_dir which is equal to mnt_fsname of
+ * input mntent and replace it by new one.
+ */
+static void FAST_FUNC update_mtab_entry_on_move(const struct mntent *mp)
+{
+ struct mntent *entries, *m;
+ int i, count;
+ FILE *mountTable;
+
+ mountTable = setmntent(bb_path_mtab_file, "r");
+ if (!mountTable) {
+ bb_perror_msg(bb_path_mtab_file);
+ return;
+ }
+
+ entries = NULL;
+ count = 0;
+ while ((m = getmntent(mountTable)) != NULL) {
+ entries = xrealloc_vector(entries, 3, count);
+ entries[count].mnt_fsname = xstrdup(m->mnt_fsname);
+ entries[count].mnt_dir = xstrdup(m->mnt_dir);
+ entries[count].mnt_type = xstrdup(m->mnt_type);
+ entries[count].mnt_opts = xstrdup(m->mnt_opts);
+ entries[count].mnt_freq = m->mnt_freq;
+ entries[count].mnt_passno = m->mnt_passno;
+ count++;
+ }
+ endmntent(mountTable);
+
+ mountTable = setmntent(bb_path_mtab_file, "w");
+ if (mountTable) {
+ for (i = 0; i < count; i++) {
+ if (strcmp(entries[i].mnt_dir, mp->mnt_fsname) != 0)
+ addmntent(mountTable, &entries[i]);
+ else
+ addmntent(mountTable, mp);
+ }
+ endmntent(mountTable);
+ } else if (errno != EROFS)
+ bb_perror_msg(bb_path_mtab_file);
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ for (i = 0; i < count; i++) {
+ free(entries[i].mnt_fsname);
+ free(entries[i].mnt_dir);
+ free(entries[i].mnt_type);
+ free(entries[i].mnt_opts);
+ }
+ free(entries);
+ }
+}
+#endif
+
+#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 rc;
+
+ 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
+
+// Append mount options to string
+static void append_mount_options(char **oldopts, const char *newopts)
+{
+ if (*oldopts && **oldopts) {
+ // Do not insert options which are already there
+ while (newopts[0]) {
+ char *p;
+ int len = strlen(newopts);
+ p = strchr(newopts, ',');
+ if (p) len = p - newopts;
+ p = *oldopts;
+ while (1) {
+ if (!strncmp(p, newopts, len)
+ && (p[len] == ',' || p[len] == '\0'))
+ goto skip;
+ p = strchr(p,',');
+ if (!p) break;
+ p++;
+ }
+ p = xasprintf("%s,%.*s", *oldopts, len, newopts);
+ free(*oldopts);
+ *oldopts = p;
+ skip:
+ newopts += len;
+ while (newopts[0] == ',') newopts++;
+ }
+ } else {
+ if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
+ *oldopts = xstrdup(newopts);
+ }
+}
+
+// Use the mount_options list to parse options into flags.
+// Also update list of unrecognized options if unrecognized != NULL
+static unsigned long parse_mount_options(char *options, char **unrecognized)
+{
+ unsigned 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++) {
+ unsigned opt_len = strlen(option_str);
+
+ if (strncasecmp(option_str, options, opt_len) == 0
+ && (options[opt_len] == '\0'
+ /* or is it "comment=" thingy in fstab? */
+ IF_FEATURE_MOUNT_FSTAB(IF_DESKTOP( || option_str[opt_len-1] == '=' ))
+ )
+ ) {
+ unsigned long fl = mount_options[i];
+ if (fl & BB_MS_INVERTED_VALUE)
+ flags &= fl;
+ else
+ flags |= fl;
+ goto found;
+ }
+ option_str += opt_len + 1;
+ }
+ // We did not recognize this option.
+ // If "unrecognized" is not NULL, append option there.
+ // Note that we should not append *empty* option -
+ // in this case we want to pass NULL, not "", to "data"
+ // parameter of mount(2) syscall.
+ // This is crucial for filesystems that don't accept
+ // any arbitrary mount options, like cgroup fs:
+ // "mount -t cgroup none /mnt"
+ if (options[0] && unrecognized) {
+ // Add it to strflags, to pass on to kernel
+ char *p = *unrecognized;
+ unsigned len = p ? strlen(p) : 0;
+ *unrecognized = p = xrealloc(p, len + strlen(options) + 2);
+
+ // Comma separated if it's not the first one
+ if (len) p[len++] = ',';
+ strcpy(p + len, options);
+ }
+ found:
+ 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 = NULL;
+ 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) == 0 && isspace(buf[5]))
+ goto next;
+ fs = skip_whitespace(buf);
+ if (*fs == '#' || *fs == '*' || !*fs)
+ goto next;
+
+ llist_add_to_end(&list, xstrdup(fs));
+ next:
+ 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
+
+// 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, unsigned long vfsflags, char *filteropts)
+{
+ int rc = 0;
+
+ if (FAKE_IT) {
+ 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 (HELPERS_ALLOWED && rc && mp->mnt_type) {
+ char *args[8];
+ int errno_save = errno;
+ args[0] = xasprintf("mount.%s", mp->mnt_type);
+ rc = 1;
+ if (FAKE_IT)
+ args[rc++] = (char *)"-f";
+ if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
+ args[rc++] = (char *)"-n";
+ args[rc++] = mp->mnt_fsname;
+ args[rc++] = mp->mnt_dir;
+ if (filteropts) {
+ args[rc++] = (char *)"-o";
+ args[rc++] = filteropts;
+ }
+ args[rc] = NULL;
+ rc = spawn_and_wait(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",
+ 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 (USE_MTAB && !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_perror_msg(bb_path_mtab_file);
+ goto ret;
+ }
+
+ // 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;
+ while (i > 0 && mp->mnt_dir[i] == '/')
+ mp->mnt_dir[i--] = '\0';
+
+ // Convert to canonical pathnames as needed
+ mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
+ fsname = NULL;
+ 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
+#if ENABLE_FEATURE_MTAB_SUPPORT
+ if (vfsflags & MS_MOVE)
+ update_mtab_entry_on_move(mp);
+ else
+#endif
+ 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 source tree.
+ *
+ * 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.
+ */
+
+#define MOUNTPORT 635
+#define MNTPATHLEN 1024
+#define MNTNAMLEN 255
+#define FHSIZE 32
+#define FHSIZE3 64
+
+typedef char fhandle[FHSIZE];
+
+typedef struct {
+ unsigned int fhandle3_len;
+ char *fhandle3_val;
+} fhandle3;
+
+enum mountstat3 {
+ MNT_OK = 0,
+ MNT3ERR_PERM = 1,
+ MNT3ERR_NOENT = 2,
+ MNT3ERR_IO = 5,
+ MNT3ERR_ACCES = 13,
+ MNT3ERR_NOTDIR = 20,
+ MNT3ERR_INVAL = 22,
+ MNT3ERR_NAMETOOLONG = 63,
+ MNT3ERR_NOTSUPP = 10004,
+ MNT3ERR_SERVERFAULT = 10006,
+};
+typedef enum mountstat3 mountstat3;
+
+struct fhstatus {
+ unsigned int fhs_status;
+ union {
+ fhandle fhs_fhandle;
+ } fhstatus_u;
+};
+typedef struct fhstatus fhstatus;
+
+struct mountres3_ok {
+ fhandle3 fhandle;
+ struct {
+ unsigned int auth_flavours_len;
+ char *auth_flavours_val;
+ } auth_flavours;
+};
+typedef struct mountres3_ok mountres3_ok;
+
+struct mountres3 {
+ mountstat3 fhs_status;
+ union {
+ mountres3_ok mountinfo;
+ } mountres3_u;
+};
+typedef struct mountres3 mountres3;
+
+typedef char *dirpath;
+
+typedef char *name;
+
+typedef struct mountbody *mountlist;
+
+struct mountbody {
+ name ml_hostname;
+ dirpath ml_directory;
+ mountlist ml_next;
+};
+typedef struct mountbody mountbody;
+
+typedef struct groupnode *groups;
+
+struct groupnode {
+ name gr_name;
+ groups gr_next;
+};
+typedef struct groupnode groupnode;
+
+typedef struct exportnode *exports;
+
+struct exportnode {
+ dirpath ex_dir;
+ groups ex_groups;
+ exports ex_next;
+};
+typedef struct exportnode exportnode;
+
+struct ppathcnf {
+ int pc_link_max;
+ short pc_max_canon;
+ short pc_max_input;
+ short pc_name_max;
+ short pc_path_max;
+ short pc_pipe_buf;
+ uint8_t pc_vdisable;
+ char pc_xxx;
+ short pc_mask[2];
+};
+typedef struct ppathcnf ppathcnf;
+
+#define MOUNTPROG 100005
+#define MOUNTVERS 1
+
+#define MOUNTPROC_NULL 0
+#define MOUNTPROC_MNT 1
+#define MOUNTPROC_DUMP 2
+#define MOUNTPROC_UMNT 3
+#define MOUNTPROC_UMNTALL 4
+#define MOUNTPROC_EXPORT 5
+#define MOUNTPROC_EXPORTALL 6
+
+#define MOUNTVERS_POSIX 2
+
+#define MOUNTPROC_PATHCONF 7
+
+#define MOUNT_V3 3
+
+#define MOUNTPROC3_NULL 0
+#define MOUNTPROC3_MNT 1
+#define MOUNTPROC3_DUMP 2
+#define MOUNTPROC3_UMNT 3
+#define MOUNTPROC3_UMNTALL 4
+#define MOUNTPROC3_EXPORT 5
+
+enum {
+#ifndef NFS_FHSIZE
+ NFS_FHSIZE = 32,
+#endif
+#ifndef NFS_PORT
+ NFS_PORT = 2049
+#endif
+};
+
+/*
+ * We want to be able to compile mount on old kernels in such a way
+ * that the binary will work well on more recent kernels.
+ * Thus, if necessary we teach nfsmount.c the structure of new fields
+ * that will come later.
+ *
+ * Moreover, the new kernel includes conflict with glibc includes
+ * so it is easiest to ignore the kernel altogether (at compile time).
+ */
+
+struct nfs2_fh {
+ char data[32];
+};
+struct nfs3_fh {
+ unsigned short size;
+ unsigned char data[64];
+};
+
+struct nfs_mount_data {
+ int version; /* 1 */
+ int fd; /* 1 */
+ struct nfs2_fh old_root; /* 1 */
+ int flags; /* 1 */
+ int rsize; /* 1 */
+ int wsize; /* 1 */
+ int timeo; /* 1 */
+ int retrans; /* 1 */
+ int acregmin; /* 1 */
+ int acregmax; /* 1 */
+ int acdirmin; /* 1 */
+ int acdirmax; /* 1 */
+ struct sockaddr_in addr; /* 1 */
+ char hostname[256]; /* 1 */
+ int namlen; /* 2 */
+ unsigned int bsize; /* 3 */
+ struct nfs3_fh root; /* 4 */
+};
+
+/* bits in the flags field */
+enum {
+ NFS_MOUNT_SOFT = 0x0001, /* 1 */
+ NFS_MOUNT_INTR = 0x0002, /* 1 */
+ NFS_MOUNT_SECURE = 0x0004, /* 1 */
+ NFS_MOUNT_POSIX = 0x0008, /* 1 */
+ NFS_MOUNT_NOCTO = 0x0010, /* 1 */
+ NFS_MOUNT_NOAC = 0x0020, /* 1 */
+ NFS_MOUNT_TCP = 0x0040, /* 2 */
+ NFS_MOUNT_VER3 = 0x0080, /* 3 */
+ NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
+ NFS_MOUNT_NONLM = 0x0200, /* 3 */
+ NFS_MOUNT_NOACL = 0x0800, /* 4 */
+ 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 uint8_t nfs_err_stat[] = {
+ 1, 2, 5, 6, 13, 17,
+ 19, 20, 21, 22, 27, 28,
+ 30, 63, 66, 69, 70, 71
+};
+#if ( \
+ EPERM | ENOENT | EIO | ENXIO | EACCES| EEXIST | \
+ ENODEV| ENOTDIR | EISDIR | EINVAL| EFBIG | ENOSPC | \
+ EROFS | ENAMETOOLONG| ENOTEMPTY| EDQUOT| ESTALE| EREMOTE) < 256
+typedef uint8_t nfs_err_type;
+#else
+typedef uint16_t nfs_err_type;
+#endif
+static const nfs_err_type nfs_err_errnum[] = {
+ EPERM , ENOENT , EIO , ENXIO , EACCES, EEXIST,
+ ENODEV, ENOTDIR , EISDIR , EINVAL, EFBIG , ENOSPC,
+ EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE
+};
+static char *nfs_strerror(int status)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
+ if (nfs_err_stat[i] == status)
+ return strerror(nfs_err_errnum[i]);
+ }
+ return xasprintf("unknown nfs status return value: %d", status);
+}
+
+static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
+{
+ return xdr_opaque(xdrs, objp, FHSIZE);
+}
+
+static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
+{
+ if (!xdr_u_int(xdrs, &objp->fhs_status))
+ return FALSE;
+ if (objp->fhs_status == 0)
+ return xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle);
+ return TRUE;
+}
+
+static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
+{
+ return xdr_string(xdrs, objp, MNTPATHLEN);
+}
+
+static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
+{
+ return xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
+ (unsigned int *) &objp->fhandle3_len,
+ FHSIZE3);
+}
+
+static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
+{
+ if (!xdr_fhandle3(xdrs, &objp->fhandle))
+ return FALSE;
+ return xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
+ &(objp->auth_flavours.auth_flavours_len),
+ ~0,
+ sizeof(int),
+ (xdrproc_t) xdr_int);
+}
+
+static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
+{
+ return xdr_enum(xdrs, (enum_t *) objp);
+}
+
+static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
+{
+ if (!xdr_mountstat3(xdrs, &objp->fhs_status))
+ return FALSE;
+ if (objp->fhs_status == MNT_OK)
+ return xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo);
+ return TRUE;
+}
+
+#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,2,18))
+ 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;
+
+ 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)
+{
+ 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
+
+/* TODO */
+static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
+{
+ 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 NOINLINE int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
+{
+ CLIENT *mclient;
+ char *hostname;
+ char *pathname;
+ char *mounthost;
+ /* prior to 2.6.23, kernel took NFS options in a form of this struct
+ * only. 2.6.23+ looks at data->version, and if it's not 1..6,
+ * then data pointer is interpreted as a string. */
+ 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. gcc 4.3.1 likes this combination: */
+ smallint tcp;
+ smallint soft;
+ int intr;
+ int posix;
+ int nocto;
+ int noac;
+ int nordirplus;
+ int nolock;
+ int noacl;
+
+ find_kernel_nfs_mount_version();
+
+ daemonized = 0;
+ mounthost = NULL;
+ retval = ETIMEDOUT;
+ msock = fsock = -1;
+ mclient = NULL;
+
+ /* NB: hostname, mounthost, filteropts must be free()d prior to return */
+
+ filteropts = xstrdup(filteropts); /* going to trash it later... */
+
+ hostname = xstrdup(mp->mnt_fsname);
+ /* mount_main() guarantees that ':' is there */
+ s = strchr(hostname, ':');
+ pathname = s + 1;
+ *s = '\0';
+ /* Ignore all but first hostname in replicated mounts
+ * until they can be fully supported. (mack@sgi.com) */
+ s = strchr(hostname, ',');
+ if (s) {
+ *s = '\0';
+ bb_error_msg("warning: multiple hostnames not supported");
+ }
+
+ server_addr.sin_family = AF_INET;
+ if (!inet_aton(hostname, &server_addr.sin_addr)) {
+ hp = gethostbyname(hostname);
+ if (hp == NULL) {
+ bb_herror_msg("%s", hostname);
+ goto fail;
+ }
+ if (hp->h_length != (int)sizeof(struct in_addr)) {
+ bb_error_msg_and_die("only IPv4 is supported");
+ }
+ memcpy(&server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
+ }
+
+ memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
+
+ /* add IP address to mtab options for use when unmounting */
+
+ if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
+ mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
+ } else {
+ char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
+ mp->mnt_opts[0] ? "," : "",
+ inet_ntoa(server_addr.sin_addr));
+ free(mp->mnt_opts);
+ mp->mnt_opts = tmp;
+ }
+
+ /* Set default options.
+ * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
+ * let the kernel decide.
+ * timeo is filled in after we know whether it'll be TCP or UDP. */
+ memset(&data, 0, sizeof(data));
+ data.retrans = 3;
+ data.acregmin = 3;
+ data.acregmax = 60;
+ data.acdirmin = 30;
+ data.acdirmax = 60;
+ data.namlen = NAME_MAX;
+
+ soft = 0;
+ intr = 0;
+ posix = 0;
+ nocto = 0;
+ nolock = 0;
+ noac = 0;
+ nordirplus = 0;
+ noacl = 0;
+ retry = 10000; /* 10000 minutes ~ 1 week */
+ tcp = 1; /* nfs-utils uses tcp per default */
+
+ 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;
+ case -1: // unknown
+ if (vfsflags & MS_REMOUNT)
+ continue;
+ }
+
+ val = xatoi_positive(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;
+ }
+ }
+ 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"
+ "acl\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
+ 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;
+ case 12: // acl
+ noacl = !val;
+ break;
+ default:
+ bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
+ goto fail;
+ }
+ }
+ }
+ proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
+
+ data.flags = (soft ? NFS_MOUNT_SOFT : 0)
+ | (intr ? NFS_MOUNT_INTR : 0)
+ | (posix ? NFS_MOUNT_POSIX : 0)
+ | (nocto ? NFS_MOUNT_NOCTO : 0)
+ | (noac ? NFS_MOUNT_NOAC : 0)
+ | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0)
+ | (noacl ? NFS_MOUNT_NOACL : 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 {
+ hp = gethostbyname(mounthost);
+ if (hp == NULL) {
+ bb_herror_msg("%s", mounthost);
+ goto fail;
+ }
+ if (hp->h_length != (int)sizeof(struct in_addr)) {
+ bb_error_msg_and_die("only IPv4 is supported");
+ }
+ mount_server_addr.sin_family = AF_INET;
+ memcpy(&mount_server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
+ }
+ }
+
+ /*
+ * 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;
+ }
+ }
+ prevt = t;
+ t = time(NULL);
+ if (t >= timeout)
+ /* TODO error message */
+ goto fail;
+
+ goto retry;
+ }
+
+ prepare_kernel_data:
+
+ if (nfsvers == 2) {
+ if (status.nfsv2.fhs_status != 0) {
+ bb_error_msg("%s:%s failed, reason given by server: %s",
+ hostname, pathname,
+ nfs_strerror(status.nfsv2.fhs_status));
+ goto fail;
+ }
+ memcpy(data.root.data,
+ (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
+ NFS_FHSIZE);
+ data.root.size = NFS_FHSIZE;
+ memcpy(data.old_root.data,
+ (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
+ NFS_FHSIZE);
+ } else {
+ fhandle3 *my_fhandle;
+ if (status.nfsv3.fhs_status != 0) {
+ bb_error_msg("%s:%s failed, reason given by server: %s",
+ hostname, pathname,
+ nfs_strerror(status.nfsv3.fhs_status));
+ goto fail;
+ }
+ my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
+ memset(data.old_root.data, 0, NFS_FHSIZE);
+ memset(&data.root, 0, sizeof(data.root));
+ data.root.size = my_fhandle->fhandle3_len;
+ memcpy(data.root.data,
+ (char *) my_fhandle->fhandle3_val,
+ my_fhandle->fhandle3_len);
+
+ data.flags |= NFS_MOUNT_VER3;
+ }
+
+ /* Create nfs socket for kernel */
+ if (tcp) {
+ if (nfs_mount_version < 3) {
+ bb_error_msg("NFS over TCP is not supported");
+ goto fail;
+ }
+ fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ } else
+ fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (fsock < 0) {
+ bb_perror_msg("nfs socket");
+ goto fail;
+ }
+ if (bindresvport(fsock, 0) < 0) {
+ bb_perror_msg("nfs bindresvport");
+ goto fail;
+ }
+ if (port == 0) {
+ server_addr.sin_port = PMAPPORT;
+ port = pmap_getport(&server_addr, nfsprog, nfsvers,
+ tcp ? IPPROTO_TCP : IPPROTO_UDP);
+ if (port == 0)
+ port = NFS_PORT;
+ }
+ server_addr.sin_port = htons(port);
+
+ /* Prepare data structure for kernel */
+ data.fd = fsock;
+ memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
+ strncpy(data.hostname, hostname, sizeof(data.hostname));
+
+ /* Clean up */
+ auth_destroy(mclient->cl_auth);
+ clnt_destroy(mclient);
+ close(msock);
+ msock = -1;
+
+ 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;
+ }
+ }
+
+ /* Perform actual mount */
+ do_mount:
+ 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);
+ }
+ close(msock);
+ }
+ if (fsock >= 0)
+ close(fsock);
+
+ ret:
+ free(hostname);
+ free(mounthost);
+ free(filteropts);
+ return retval;
+}
+
+#else // !ENABLE_FEATURE_MOUNT_NFS
+
+/* Linux 2.6.23+ supports nfs mounts with options passed as a string.
+ * For older kernels, you must build busybox with ENABLE_FEATURE_MOUNT_NFS.
+ * (However, note that then you lose any chances that NFS over IPv6 would work).
+ */
+static int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
+{
+ len_and_sockaddr *lsa;
+ char *opts;
+ char *end;
+ char *dotted;
+ int ret;
+
+# if ENABLE_FEATURE_IPV6
+ end = strchr(mp->mnt_fsname, ']');
+ if (end && end[1] == ':')
+ end++;
+ else
+# endif
+ /* mount_main() guarantees that ':' is there */
+ end = strchr(mp->mnt_fsname, ':');
+
+ *end = '\0';
+ lsa = xhost2sockaddr(mp->mnt_fsname, /*port:*/ 0);
+ *end = ':';
+ dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
+ if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
+ opts = xasprintf("%s%saddr=%s",
+ filteropts ? filteropts : "",
+ filteropts ? "," : "",
+ dotted
+ );
+ if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
+ ret = mount_it_now(mp, vfsflags, opts);
+ if (ENABLE_FEATURE_CLEAN_UP) free(opts);
+
+ return ret;
+}
+
+#endif // !ENABLE_FEATURE_MOUNT_NFS
+
+// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
+// type detection. Returns 0 for success, nonzero for failure.
+// NB: mp->xxx fields may be trashed on exit
+static int singlemount(struct mntent *mp, int ignore_busy)
+{
+ int rc = -1;
+ unsigned long vfsflags;
+ char *loopFile = NULL, *filteropts = NULL;
+ llist_t *fl = NULL;
+ struct stat st;
+
+ errno = 0;
+
+ vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
+
+ // Treat fstype "auto" as unspecified
+ if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
+ mp->mnt_type = NULL;
+
+ // Might this be a virtual filesystem?
+ if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
+ char *args[35];
+ char *s;
+ int n;
+ // fsname: "cmd#arg1#arg2..."
+ // WARNING: allows execution of arbitrary commands!
+ // Try "mount 'sh#-c#sh' bogus_dir".
+ // It is safe ONLY because non-root
+ // cannot use two-argument mount command
+ // and using one-argument "mount 'sh#-c#sh'" doesn't work:
+ // "mount: can't find sh#-c#sh in /etc/fstab"
+ // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
+
+ s = mp->mnt_fsname;
+ n = 0;
+ args[n++] = s;
+ while (*s && n < 35 - 2) {
+ if (*s++ == '#' && *s != '#') {
+ s[-1] = '\0';
+ args[n++] = s;
+ }
+ }
+ args[n++] = mp->mnt_dir;
+ args[n] = NULL;
+ rc = spawn_and_wait(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]
+ ) {
+ int len;
+ char c;
+ char *hostname, *share;
+ char *dotted, *ip;
+ len_and_sockaddr *lsa;
+
+ // Parse mp->mnt_fsname of the form "//hostname/share[/dir1/dir2]"
+
+ hostname = mp->mnt_fsname + 2;
+ len = strcspn(hostname, "/\\");
+ share = hostname + len + 1;
+ if (len == 0 // 3rd char is a [back]slash (IOW: empty hostname)
+ || share[-1] == '\0' // no [back]slash after hostname
+ || share[0] == '\0' // empty share name
+ ) {
+ goto report_error;
+ }
+ c = share[-1];
+ share[-1] = '\0';
+ len = strcspn(share, "/\\");
+
+ // "unc=\\hostname\share" option is mandatory
+ // after CIFS option parsing was rewritten in Linux 3.4.
+ // Must use backslashes.
+ // If /dir1/dir2 is present, also add "prefixpath=dir1/dir2"
+ {
+ char *unc = xasprintf(
+ share[len] != '\0' /* "/dir1/dir2" exists? */
+ ? "unc=\\\\%s\\%.*s,prefixpath=%s"
+ : "unc=\\\\%s\\%.*s",
+ hostname,
+ len, share,
+ share + len + 1 /* "dir1/dir2" */
+ );
+ parse_mount_options(unc, &filteropts);
+ if (ENABLE_FEATURE_CLEAN_UP) free(unc);
+ }
+
+ lsa = host2sockaddr(hostname, 0);
+ share[-1] = c;
+ if (!lsa)
+ goto report_error;
+
+ // Insert "ip=..." option into options
+ dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
+ if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
+ ip = xasprintf("ip=%s", dotted);
+ if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
+ parse_mount_options(ip, &filteropts);
+ if (ENABLE_FEATURE_CLEAN_UP) free(ip);
+
+ mp->mnt_type = (char*)"cifs";
+ rc = mount_it_now(mp, vfsflags, filteropts);
+
+ goto report_error;
+ }
+
+ // Might this be an NFS filesystem?
+ if ((!mp->mnt_type || strncmp(mp->mnt_type, "nfs", 3) == 0)
+ && strchr(mp->mnt_fsname, ':') != NULL
+ ) {
+ if (!mp->mnt_type)
+ mp->mnt_type = (char*)"nfs";
+ 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, /*ro:*/ (vfsflags & MS_RDONLY)) < 0) {
+ if (errno == EPERM || errno == EACCES)
+ bb_error_msg(bb_msg_perm_denied_are_you_root);
+ else
+ bb_perror_msg("can't 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))) {
+ char *next;
+ for (;;) {
+ next = mp->mnt_type ? strchr(mp->mnt_type, ',') : NULL;
+ if (next)
+ *next = '\0';
+ rc = mount_it_now(mp, vfsflags, filteropts);
+ if (rc == 0 || !next)
+ break;
+ mp->mnt_type = next + 1;
+ }
+ } 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 == 0)
+ break;
+ }
+ }
+
+ // If mount failed, clean up loop file (if any).
+ if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
+ del_loop(mp->mnt_fsname);
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(loopFile);
+ free(mp->mnt_fsname);
+ }
+ }
+
+ report_error:
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(filteropts);
+
+ if (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;
+}
+
+// -O support
+// -O interprets a list of filter options which select whether a mount
+// point will be mounted: only mounts with options matching *all* filtering
+// options will be selected.
+// By default each -O filter option must be present in the list of mount
+// options, but if it is prefixed by "no" then it must be absent.
+// For example,
+// -O a,nob,c matches -o a,c but fails to match -o a,b,c
+// (and also fails to match -o a because -o c is absent).
+//
+// It is different from -t in that each option is matched exactly; a leading
+// "no" at the beginning of one option does not negate the rest.
+static int match_opt(const char *fs_opt_in, const char *O_opt)
+{
+ if (!O_opt)
+ return 1;
+
+ while (*O_opt) {
+ const char *fs_opt = fs_opt_in;
+ int O_len;
+ int match;
+
+ // If option begins with "no" then treat as an inverted match:
+ // matching is a failure
+ match = 0;
+ if (O_opt[0] == 'n' && O_opt[1] == 'o') {
+ match = 1;
+ O_opt += 2;
+ }
+ // Isolate the current O option
+ O_len = strchrnul(O_opt, ',') - O_opt;
+ // Check for a match against existing options
+ while (1) {
+ if (strncmp(fs_opt, O_opt, O_len) == 0
+ && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
+ ) {
+ if (match)
+ return 0; // "no" prefix, but option found
+ match = 1; // current O option found, go check next one
+ break;
+ }
+ fs_opt = strchr(fs_opt, ',');
+ if (!fs_opt)
+ break;
+ fs_opt++;
+ }
+ if (match == 0)
+ return 0; // match wanted but not found
+ if (O_opt[O_len] == '\0') // end?
+ break;
+ // Step to the next O option
+ O_opt += O_len + 1;
+ }
+ // If we get here then everything matched
+ return 1;
+}
+
+// Parse options, if necessary parse fstab/mtab, and call singlemount for
+// each directory to be mounted.
+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;
+ int rc = EXIT_SUCCESS;
+ unsigned long cmdopt_flags;
+ unsigned opt;
+ struct mntent mtpair[2], *mtcur = mtpair;
+ IF_NOT_DESKTOP(const int nonroot = 0;)
+
+ IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
+
+ INIT_G();
+
+ // 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;
+
+ // Parse remaining options
+ // Max 2 params; -o is a list, -v is a counter
+ opt_complementary = "?2o::" IF_FEATURE_MOUNT_VERBOSE("vv");
+ opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
+ IF_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;
+
+ // 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") == 0) continue;
+
+ if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
+ 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(bb_msg_you_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, /*ignore_busy:*/ 0);
+ return rc;
+ }
+ storage_path = bb_simplify_path(argv[0]); // malloced
+ }
+
+ // Past this point, we are handling either "mount -a [opts]"
+ // or "mount [opts] single_param"
+
+ cmdopt_flags = parse_mount_options(cmdopts, NULL);
+ if (nonroot && (cmdopt_flags & ~MS_SILENT)) // Non-root users cannot specify flags
+ bb_error_msg_and_die(bb_msg_you_must_be_root);
+
+ // If we have a shared subtree flag, don't worry about fstab or mtab.
+ if (ENABLE_FEATURE_MOUNT_FLAGS
+ && (cmdopt_flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
+ ) {
+ // verbose_mount(source, target, type, flags, data)
+ rc = verbose_mount("", argv[0], "", cmdopt_flags, "");
+ if (rc)
+ bb_simple_perror_msg_and_die(argv[0]);
+ return rc;
+ }
+
+ // Open either fstab or mtab
+ fstabname = "/etc/fstab";
+ if (cmdopt_flags & 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("can't read '%s'", fstabname);
+
+ // 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) != 0
+ && strcmp(storage_path, mtcur->mnt_fsname) != 0
+ && strcmp(argv[0], mtcur->mnt_dir) != 0
+ && strcmp(storage_path, mtcur->mnt_dir) != 0
+ ) {
+ continue; // no
+ }
+
+ // Remember this entry. Something later may have
+ // overmounted it, and we want the _last_ match.
+ mtcur = mtother;
+
+ // If we're mounting all
+ } else {
+ struct mntent *mp;
+ // No, mount -a won't mount anything,
+ // even user mounts, for mere humans
+ if (nonroot)
+ bb_error_msg_and_die(bb_msg_you_must_be_root);
+
+ // Does type match? (NULL matches always)
+ if (!match_fstype(mtcur, fstype))
+ continue;
+
+ // 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;
+ }
+
+ // Does (at least one) option match?
+ // (NULL matches always)
+ if (!match_opt(mtcur->mnt_opts, O_optmatch))
+ continue;
+
+ resolve_mount_spec(&mtcur->mnt_fsname);
+
+ // NFS mounts want this to be xrealloc-able
+ mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
+
+ // If nothing is mounted on this directory...
+ // (otherwise repeated "mount -a" mounts everything again)
+ mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
+ // We do not check fsname match of found mount point -
+ // "/" may have fsname of "/dev/root" while fstab
+ // says "/dev/something_else".
+ if (mp) {
+ if (verbose) {
+ bb_error_msg("according to %s, "
+ "%s is already mounted on %s",
+ bb_path_mtab_file,
+ mp->mnt_fsname, mp->mnt_dir);
+ }
+ } else {
+ // ...mount this thing
+ if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
+ // Count number of failed mounts
+ rc++;
+ }
+ }
+ free(mtcur->mnt_opts);
+ }
+ }
+
+ // End of fstab/mtab is reached.
+ // Were we looking for something specific?
+ if (argv[0]) { // yes
+ unsigned 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;
+ }
+#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(bb_msg_you_must_be_root);
+ }
+
+ //util-linux-2.12 does not do this check.
+ //// If nothing is mounted on this directory...
+ //// (otherwise repeated "mount FOO" mounts FOO again)
+ //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
+ //if (mp) {
+ // bb_error_msg("according to %s, "
+ // "%s is already mounted on %s",
+ // bb_path_mtab_file,
+ // mp->mnt_fsname, mp->mnt_dir);
+ //} else {
+ // ...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, /*ignore_busy:*/ 0);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(mtcur->mnt_opts);
+ //}
+ }
+
+ //ret:
+ if (ENABLE_FEATURE_CLEAN_UP)
+ endmntent(fstab);
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(storage_path);
+ free(cmdopts);
+ }
+
+//TODO: exitcode should be ORed mask of (from "man mount"):
+// 0 success
+// 1 incorrect invocation or permissions
+// 2 system error (out of memory, cannot fork, no more loop devices)
+// 4 internal mount bug or missing nfs support in mount
+// 8 user interrupt
+//16 problems writing or locking /etc/mtab
+//32 mount failure
+//64 some mount succeeded
+ return rc;
+}
diff --git a/ap/app/busybox/src/util-linux/pivot_root.c b/ap/app/busybox/src/util-linux/pivot_root.c
new file mode 100644
index 0000000..83f01fa
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/pivot_root.c
@@ -0,0 +1,34 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * pivot_root.c - Change root file system. Based on util-linux 2.10s
+ *
+ * busyboxed by Evin Robertson
+ * pivot_root syscall stubbed by Erik Andersen, so it will compile
+ * regardless of the kernel being used.
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//usage:#define pivot_root_trivial_usage
+//usage: "NEW_ROOT PUT_OLD"
+//usage:#define pivot_root_full_usage "\n\n"
+//usage: "Move the current root file system to PUT_OLD and make NEW_ROOT\n"
+//usage: "the new root file system"
+
+#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) {
+ /* prints "pivot_root: <strerror text>" */
+ bb_perror_nomsg_and_die();
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/util-linux/rdate.c b/ap/app/busybox/src/util-linux/rdate.c
new file mode 100644
index 0000000..6e35cd5
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/rdate.c
@@ -0,0 +1,79 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * The Rdate command will ask a time server for the RFC 868 time
+ * and optionally set the system time.
+ *
+ * by Sterling Huxley <sterling@europa.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+*/
+
+//usage:#define rdate_trivial_usage
+//usage: "[-sp] HOST"
+//usage:#define rdate_full_usage "\n\n"
+//usage: "Get and possibly set the system date/time from a remote HOST\n"
+//usage: "\n -s Set the system date/time (default)"
+//usage: "\n -p Print the date/time"
+
+#include "libbb.h"
+
+enum { 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)
+{
+ uint32_t nett;
+ int fd;
+
+ /* Add a timeout for dead or inaccessible servers */
+ alarm(10);
+ signal(SIGALRM, socket_timeout);
+
+ fd = create_and_connect_stream_or_die(host, bb_lookup_port("time", "tcp", 37));
+
+ if (safe_read(fd, &nett, 4) != 4) /* read time from server */
+ bb_error_msg_and_die("%s did not send the complete time", host);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(fd);
+
+ /* Convert from network byte order to local byte order.
+ * RFC 868 time is the number of seconds
+ * since 00:00 (midnight) 1 January 1900 GMT
+ * the RFC 868 time 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT
+ * Subtract the RFC 868 time to get Linux epoch.
+ */
+
+ return ntohl(nett) - RFC_868_BIAS;
+}
+
+int rdate_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int rdate_main(int argc UNUSED_PARAM, char **argv)
+{
+ time_t remote_time;
+ unsigned flags;
+
+ opt_complementary = "-1";
+ flags = getopt32(argv, "sp");
+
+ remote_time = askremotedate(argv[optind]);
+
+ if (!(flags & 2)) { /* no -p (-s may be present) */
+ time_t current_time;
+
+ time(¤t_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("can't set time of day");
+ }
+
+ if (flags != 1) /* not lone -s */
+ printf("%s", ctime(&remote_time));
+
+ return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/util-linux/rdev.c b/ap/app/busybox/src/util-linux/rdev.c
new file mode 100644
index 0000000..4652817
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/rdev.c
@@ -0,0 +1,33 @@
+/* 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 source tree.
+ *
+ */
+
+//usage:#define rdev_trivial_usage
+//usage: ""
+//usage:#define rdev_full_usage "\n\n"
+//usage: "Print the device node associated with the filesystem mounted at '/'"
+//usage:
+//usage:#define rdev_example_usage
+//usage: "$ rdev\n"
+//usage: "/dev/mtdblock9 /\n"
+
+#include "libbb.h"
+
+int rdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int rdev_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
+{
+ const char *root_device = find_block_device("/");
+
+ if (root_device) {
+ printf("%s /\n", root_device);
+ return EXIT_SUCCESS;
+ }
+ return EXIT_FAILURE;
+}
diff --git a/ap/app/busybox/src/util-linux/readprofile.c b/ap/app/busybox/src/util-linux/readprofile.c
new file mode 100644
index 0000000..974fe89
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/readprofile.c
@@ -0,0 +1,263 @@
+/* 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 source tree.
+ */
+
+/*
+ * 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>.
+ */
+
+//usage:#define readprofile_trivial_usage
+//usage: "[OPTIONS]"
+//usage:#define readprofile_full_usage "\n\n"
+//usage: " -m mapfile (Default: /boot/System.map)"
+//usage: "\n -p profile (Default: /proc/profile)"
+//usage: "\n -M NUM Set the profiling multiplier to NUM"
+//usage: "\n -i Print only info about the sampling step"
+//usage: "\n -v Verbose"
+//usage: "\n -a Print all symbols, even if count is 0"
+//usage: "\n -b Print individual histogram-bin counts"
+//usage: "\n -s Print individual counters within functions"
+//usage: "\n -r Reset all the counters (root only)"
+//usage: "\n -n Disable byte order auto-detection"
+
+#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/ap/app/busybox/src/util-linux/rev.c b/ap/app/busybox/src/util-linux/rev.c
new file mode 100644
index 0000000..3c1b22f
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/rev.c
@@ -0,0 +1,121 @@
+/*
+ * rev implementation for busybox
+ *
+ * Copyright (C) 2010 Marek Polacek <mmpolacek@gmail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//applet:IF_REV(APPLET(rev, BB_DIR_BIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_REV) += rev.o
+
+//config:config REV
+//config: bool "rev"
+//config: default y
+//config: help
+//config: Reverse lines of a file or files.
+
+//usage:#define rev_trivial_usage
+//usage: "[FILE]..."
+//usage:#define rev_full_usage "\n\n"
+//usage: "Reverse lines of FILE"
+
+#include "libbb.h"
+#include "unicode.h"
+
+#undef CHAR_T
+#if ENABLE_UNICODE_SUPPORT
+# define CHAR_T wchar_t
+#else
+# define CHAR_T char
+#endif
+
+/* In-place invert */
+static void strrev(CHAR_T *s, int len)
+{
+ int i;
+
+ if (len != 0) {
+ len--;
+ if (len != 0 && s[len] == '\n')
+ len--;
+ }
+
+ for (i = 0; i < len; i++, len--) {
+ CHAR_T c = s[i];
+ s[i] = s[len];
+ s[len] = c;
+ }
+}
+
+int rev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int rev_main(int argc UNUSED_PARAM, char **argv)
+{
+ int retval;
+ size_t bufsize;
+ char *buf;
+
+ init_unicode();
+
+ getopt32(argv, "");
+ argv += optind;
+ if (!argv[0])
+ argv = (char **)&bb_argv_dash;
+
+ retval = EXIT_SUCCESS;
+ bufsize = 256;
+ buf = xmalloc(bufsize);
+ do {
+ size_t pos;
+ FILE *fp;
+
+ fp = fopen_or_warn_stdin(*argv++);
+ if (!fp) {
+ retval = EXIT_FAILURE;
+ continue;
+ }
+
+ pos = 0;
+ while (1) {
+ /* Read one line */
+ buf[bufsize - 1] = 1; /* not 0 */
+ if (!fgets(buf + pos, bufsize - pos, fp))
+ break; /* EOF/error */
+ if (buf[bufsize - 1] == '\0' /* fgets filled entire buffer */
+ && buf[bufsize - 2] != '\n' /* and did not read '\n' */
+ && !feof(fp)
+ ) {
+ /* Line is too long, extend buffer */
+ pos = bufsize - 1;
+ bufsize += 64 + bufsize / 8;
+ buf = xrealloc(buf, bufsize);
+ continue;
+ }
+
+ /* Process and print it */
+#if ENABLE_UNICODE_SUPPORT
+ {
+ wchar_t *tmp = xmalloc(bufsize * sizeof(wchar_t));
+ /* Convert to wchar_t (might error out!) */
+ int len = mbstowcs(tmp, buf, bufsize);
+ if (len >= 0) {
+ strrev(tmp, len);
+ /* Convert back to char */
+ wcstombs(buf, tmp, bufsize);
+ }
+ free(tmp);
+ }
+#else
+ strrev(buf, strlen(buf));
+#endif
+ fputs(buf, stdout);
+ }
+ fclose(fp);
+ } while (*argv);
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(buf);
+
+ fflush_stdout_and_exit(retval);
+}
diff --git a/ap/app/busybox/src/util-linux/rtcwake.c b/ap/app/busybox/src/util-linux/rtcwake.c
new file mode 100644
index 0000000..735a298
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/rtcwake.c
@@ -0,0 +1,226 @@
+/*
+ * 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 source tree.
+ *
+ * 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.
+ */
+
+//usage:#define rtcwake_trivial_usage
+//usage: "[-a | -l | -u] [-d DEV] [-m MODE] [-s SEC | -t TIME]"
+//usage:#define rtcwake_full_usage "\n\n"
+//usage: "Enter a system sleep state until specified wakeup time\n"
+//usage: IF_LONG_OPTS(
+//usage: "\n -a,--auto Read clock mode from adjtime"
+//usage: "\n -l,--local Clock is set to local time"
+//usage: "\n -u,--utc Clock is set to UTC time"
+//usage: "\n -d,--device=DEV Specify the RTC device"
+//usage: "\n -m,--mode=MODE Set the sleep state (default: standby)"
+//usage: "\n -s,--seconds=SEC Set the timeout in SEC seconds from now"
+//usage: "\n -t,--time=TIME Set the timeout to TIME seconds from epoch"
+//usage: )
+//usage: IF_NOT_LONG_OPTS(
+//usage: "\n -a Read clock mode from adjtime"
+//usage: "\n -l Clock is set to local time"
+//usage: "\n -u Clock is set to UTC time"
+//usage: "\n -d DEV Specify the RTC device"
+//usage: "\n -m MODE Set the sleep state (default: standby)"
+//usage: "\n -s SEC Set the timeout in SEC seconds from now"
+//usage: "\n -t TIME Set the timeout to TIME seconds from epoch"
+//usage: )
+
+#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 NOINLINE bool may_wakeup(const char *rtcname)
+{
+ ssize_t ret;
+ char buf[128];
+
+ /* strip "/dev/" from the rtcname here */
+ rtcname = skip_dev_pfx(rtcname);
+
+ 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 NOINLINE void setup_alarm(int fd, time_t *wakeup, time_t rtc_time)
+{
+ struct tm *ptm;
+ 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.
+ */
+ ptm = localtime(wakeup);
+
+ wake.time.tm_sec = ptm->tm_sec;
+ wake.time.tm_min = ptm->tm_min;
+ wake.time.tm_hour = ptm->tm_hour;
+ wake.time.tm_mday = ptm->tm_mday;
+ wake.time.tm_mon = ptm->tm_mon;
+ wake.time.tm_year = ptm->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)
+{
+ time_t rtc_time;
+
+ 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_LONG_OPTS
+ 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 = xatol(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);
+ {
+ struct tm tm_time;
+ rtc_read_tm(&tm_time, fd);
+ rtc_time = rtc_tm2time(&tm_time, 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, rtc_time);
+
+ sync();
+ printf("wakeup from \"%s\" at %s", suspend, ctime(&alarm_time));
+ fflush_all();
+ 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/ap/app/busybox/src/util-linux/script.c b/ap/app/busybox/src/util-linux/script.c
new file mode 100644
index 0000000..8fb991d
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/script.c
@@ -0,0 +1,204 @@
+/* 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 source tree.
+ */
+
+//usage:#define script_trivial_usage
+//usage: "[-afq" IF_SCRIPTREPLAY("t") "] [-c PROG] [OUTFILE]"
+//usage:#define script_full_usage "\n\n"
+//usage: " -a Append output"
+//usage: "\n -c PROG Run PROG, not shell"
+//usage: "\n -f Flush output after each write"
+//usage: "\n -q Quiet"
+//usage: IF_SCRIPTREPLAY(
+//usage: "\n -t Send timing to stderr"
+//usage: )
+
+#include "libbb.h"
+
+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;
+ enum {
+ OPT_a = (1 << 0),
+ OPT_c = (1 << 1),
+ OPT_f = (1 << 2),
+ OPT_q = (1 << 3),
+ OPT_t = (1 << 4),
+ };
+
+#if ENABLE_LONG_OPTS
+ 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"
+ IF_SCRIPTREPLAY("timing\0" No_argument "t")
+ ;
+
+ applet_long_options = getopt_longopts;
+#endif
+
+ opt_complementary = "?1"; /* max one arg */
+ opt = getopt32(argv, "ac:fq" IF_SCRIPTREPLAY("t") , &shell_arg);
+ //argc -= optind;
+ argv += optind;
+ if (argv[0]) {
+ fname = argv[0];
+ }
+ mode = O_CREAT|O_TRUNC|O_WRONLY;
+ if (opt & OPT_a) {
+ mode = O_CREAT|O_APPEND|O_WRONLY;
+ }
+ if (opt & OPT_c) {
+ shell_opt[1] = 'c';
+ }
+ if (!(opt & OPT_q)) {
+ printf("Script started, file is %s\n", fname);
+ }
+ shell = get_shell_name();
+
+ 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, record_signo);
+
+ /* TODO: SIGWINCH? pass window size changes down to slave? */
+
+ child_pid = xvfork();
+
+ if (child_pid) {
+ /* parent */
+#define buf bb_common_bufsiz1
+ struct pollfd pfd[2];
+ int outfd, count, loop;
+ double oldtime = ENABLE_SCRIPTREPLAY ? time(NULL) : 0;
+ smallint fd_count = 2;
+
+ outfd = xopen(fname, mode);
+ pfd[0].fd = pty;
+ pfd[0].events = POLLIN;
+ pfd[1].fd = STDIN_FILENO;
+ pfd[1].events = POLLIN;
+ ndelay_on(pty); /* this descriptor is not shared, can do this */
+ /* ndelay_on(STDIN_FILENO); - 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 && !bb_got_signal) {
+ /* 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) {
+ if (ENABLE_SCRIPTREPLAY && (opt & OPT_t)) {
+ struct timeval tv;
+ double newtime;
+
+ gettimeofday(&tv, NULL);
+ newtime = tv.tv_sec + (double) tv.tv_usec / 1000000;
+ fprintf(stderr, "%f %u\n", newtime - oldtime, count);
+ oldtime = newtime;
+ }
+ full_write(STDOUT_FILENO, buf, count);
+ full_write(outfd, buf, count);
+ if (opt & OPT_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 bb_got_signal,
+ * there still can be some buffered output. But dont 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 & OPT_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/ap/app/busybox/src/util-linux/scriptreplay.c b/ap/app/busybox/src/util-linux/scriptreplay.c
new file mode 100644
index 0000000..382f56d
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/scriptreplay.c
@@ -0,0 +1,47 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * scriptreplay - play back typescripts, using timing information
+ *
+ * pascal.bellard@ads-lu.com
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ *
+ */
+
+//usage:#define scriptreplay_trivial_usage
+//usage: "timingfile [typescript [divisor]]"
+//usage:#define scriptreplay_full_usage "\n\n"
+//usage: "Play back typescripts, using timing information"
+
+#include "libbb.h"
+
+int scriptreplay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int scriptreplay_main(int argc UNUSED_PARAM, char **argv)
+{
+ const char *script = "typescript";
+ double delay, factor = 1000000.0;
+ int fd;
+ unsigned long count;
+ FILE *tfp;
+
+ if (!argv[1])
+ bb_show_usage();
+
+ if (argv[2]) {
+ script = argv[2];
+ if (argv[3])
+ factor /= atof(argv[3]);
+ }
+
+ tfp = xfopen_for_read(argv[1]);
+ fd = xopen(script, O_RDONLY);
+ while (fscanf(tfp, "%lf %lu\n", &delay, &count) == 2) {
+ usleep(delay * factor);
+ bb_copyfd_exact_size(fd, STDOUT_FILENO, count);
+ }
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ close(fd);
+ fclose(tfp);
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/ap/app/busybox/src/util-linux/setarch.c b/ap/app/busybox/src/util-linux/setarch.c
new file mode 100644
index 0000000..7b9421a
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/setarch.c
@@ -0,0 +1,61 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * linux32/linux64 allows for changing uname emulation.
+ *
+ * Copyright 2002 Andi Kleen, SuSE Labs.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+//usage:#define setarch_trivial_usage
+//usage: "personality PROG ARGS"
+//usage:#define setarch_full_usage "\n\n"
+//usage: "Personality may be:\n"
+//usage: " linux32 Set 32bit uname emulation\n"
+//usage: " linux64 Set 64bit uname emulation"
+//usage:
+//usage:#define linux32_trivial_usage NOUSAGE_STR
+//usage:#define linux32_full_usage ""
+//usage:
+//usage:#define linux64_trivial_usage NOUSAGE_STR
+//usage:#define linux64_full_usage ""
+
+#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/ap/app/busybox/src/util-linux/swaponoff.c b/ap/app/busybox/src/util-linux/swaponoff.c
new file mode 100644
index 0000000..54867ec
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/swaponoff.c
@@ -0,0 +1,143 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini swapon/swapoff implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//usage:#define swapon_trivial_usage
+//usage: "[-a]" IF_FEATURE_SWAPON_PRI(" [-p PRI]") " [DEVICE]"
+//usage:#define swapon_full_usage "\n\n"
+//usage: "Start swapping on DEVICE\n"
+//usage: "\n -a Start swapping on all swap devices"
+//usage: IF_FEATURE_SWAPON_PRI(
+//usage: "\n -p PRI Set swap device priority"
+//usage: )
+//usage:
+//usage:#define swapoff_trivial_usage
+//usage: "[-a] [DEVICE]"
+//usage:#define swapoff_full_usage "\n\n"
+//usage: "Stop swapping on DEVICE\n"
+//usage: "\n -a Stop swapping on all swap devices"
+
+#include "libbb.h"
+#include <mntent.h>
+#ifndef __BIONIC__
+# include <sys/swap.h>
+#endif
+
+#if ENABLE_FEATURE_MOUNT_LABEL
+# include "volume_id.h"
+#else
+# define resolve_mount_spec(fsname) ((void)0)
+#endif
+
+#ifndef MNTTYPE_SWAP
+# define MNTTYPE_SWAP "swap"
+#endif
+
+#if ENABLE_FEATURE_SWAPON_PRI
+struct globals {
+ int flags;
+} FIX_ALIASING;
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define g_flags (G.flags)
+#else
+#define g_flags 0
+#endif
+#define INIT_G() do { } while (0)
+
+static int swap_enable_disable(char *device)
+{
+ int status;
+ struct stat st;
+
+ resolve_mount_spec(&device);
+ xstat(device, &st);
+
+#if ENABLE_DESKTOP
+ /* test for 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 (applet_name[5] == 'n')
+ status = swapon(device, g_flags);
+ else
+ status = swapoff(device);
+
+ if (status != 0) {
+ bb_simple_perror_msg(device);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int do_em_all(void)
+{
+ struct mntent *m;
+ FILE *f;
+ int err;
+
+ f = setmntent("/etc/fstab", "r");
+ if (f == NULL)
+ bb_perror_msg_and_die("/etc/fstab");
+
+ err = 0;
+ while ((m = getmntent(f)) != NULL) {
+ if (strcmp(m->mnt_type, MNTTYPE_SWAP) == 0) {
+ /* swapon -a should ignore entries with noauto,
+ * but swapoff -a should process them */
+ if (applet_name[5] != 'n'
+ || hasmntopt(m, MNTOPT_NOAUTO) == NULL
+ ) {
+ err += swap_enable_disable(m->mnt_fsname);
+ }
+ }
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ endmntent(f);
+
+ return err;
+}
+
+int swap_on_off_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int swap_on_off_main(int argc UNUSED_PARAM, char **argv)
+{
+ int ret;
+
+ INIT_G();
+
+#if !ENABLE_FEATURE_SWAPON_PRI
+ ret = getopt32(argv, "a");
+#else
+ if (applet_name[5] == 'n')
+ 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 (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);
+
+ return ret;
+}
diff --git a/ap/app/busybox/src/util-linux/switch_root.c b/ap/app/busybox/src/util-linux/switch_root.c
new file mode 100644
index 0000000..a301b36
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/switch_root.c
@@ -0,0 +1,219 @@
+/* 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 GPLv2, see file LICENSE in this source tree.
+ */
+
+//usage:#define switch_root_trivial_usage
+//usage: "[-c /dev/console] NEW_ROOT NEW_INIT [ARGS]"
+//usage:#define switch_root_full_usage "\n\n"
+//usage: "Free initramfs and switch to another root fs:\n"
+//usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n"
+//usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n"
+//usage: "\n -c DEV Reopen stdio to DEV after switch"
+
+#include <sys/vfs.h>
+#include <sys/mount.h>
+#include "libbb.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);
+ }
+ } else {
+ // It wasn't a directory, zap it
+ 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 st;
+ struct statfs stfs;
+ dev_t rootdev;
+
+ // Parse args (-c console)
+ opt_complementary = "-2"; // minimum 2 params
+ getopt32(argv, "+c:", &console); // '+': stop at first non-option
+ argv += optind;
+ newroot = *argv++;
+
+ // Change to new root directory and verify it's a different fs
+ xchdir(newroot);
+ xstat("/", &st);
+ rootdev = st.st_dev;
+ xstat(".", &st);
+ if (st.st_dev == rootdev || getpid() != 1) {
+ // Show usage, it says new root must be a mountpoint
+ // and we must be PID 1
+ bb_show_usage();
+ }
+
+ // 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 destroy their filesystems.
+ if (stat("/init", &st) != 0 || !S_ISREG(st.st_mode)) {
+ bb_error_msg_and_die("/init is not a regular file");
+ }
+ statfs("/", &stfs); // this never fails
+ if ((unsigned)stfs.f_type != RAMFS_MAGIC
+ && (unsigned)stfs.f_type != TMPFS_MAGIC
+ ) {
+ bb_error_msg_and_die("root filesystem is not ramfs/tmpfs");
+ }
+
+ // Zap everything out of rootdev
+ delete_contents("/", rootdev);
+
+ // Overmount / with newdir and chroot into it
+ if (mount(".", "/", NULL, MS_MOVE, NULL)) {
+ // For example, fails when newroot is not a mountpoint
+ bb_perror_msg_and_die("error moving root");
+ }
+ xchroot(".");
+ // The chdir is needed to recalculate "." and ".." links
+ /*xchdir("/"); - done in xchroot */
+
+ // If a new console specified, redirect stdin/stdout/stderr to it
+ if (console) {
+ close(0);
+ xopen(console, O_RDWR);
+ xdup2(0, 1);
+ xdup2(0, 2);
+ }
+
+ // Exec real init
+ execv(argv[0], argv);
+ bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+}
+
+/*
+From: Rob Landley <rob@landley.net>
+Date: Tue, Jun 16, 2009 at 7:47 PM
+Subject: Re: switch_root...
+
+...
+...
+...
+
+If you're _not_ running out of init_ramfs (if for example you're using initrd
+instead), you probably shouldn't use switch_root because it's the wrong tool.
+
+Basically what the sucker does is something like the following shell script:
+
+ find / -xdev | xargs rm -rf
+ cd "$1"
+ shift
+ mount --move . /
+ exec chroot . "$@"
+
+There are a couple reasons that won't work as a shell script:
+
+1) If you delete the commands out of your $PATH, your shell scripts can't run
+more commands, but you can't start using dynamically linked _new_ commands
+until after you do the chroot because the path to the dynamic linker is wrong.
+So there's a step that needs to be sort of atomic but can't be as a shell
+script. (You can work around this with static linking or very carefully laid
+out paths and sequencing, but it's brittle, ugly, and non-obvious.)
+
+2) The "find | rm" bit will acually delete everything because the mount points
+still show up (even if their contents don't), and rm -rf will then happily zap
+that. So the first line is an oversimplification of what you need to do _not_
+to descend into other filesystems and delete their contents.
+
+The reason we do this is to free up memory, by the way. Since initramfs is a
+ramfs, deleting its contents frees up the memory it uses. (We leave it with
+one remaining dentry for the new mount point, but that's ok.)
+
+Note that you cannot ever umount rootfs, for approximately the same reason you
+can't kill PID 1. The kernel tracks mount points as a doubly linked list, and
+the pointer to the start/end of that list always points to an entry that's
+known to be there (rootfs), so it never has to worry about moving that pointer
+and it never has to worry about the list being empty. (Back around 2.6.13
+there _was_ a bug that let you umount rootfs, and the system locked hard the
+instant you did so endlessly looping to find the end of the mount list and
+never stopping. They fixed it.)
+
+Oh, and the reason we mount --move _and_ do the chroot is due to the way "/"
+works. Each process has two special symlinks, ".", and "/". Each of them
+points to the dentry of a directory, and give you a location paths can start
+from. (Historically ".." was also special, because you could enter a
+directory via a symlink so backing out to the directory you came from doesn't
+necessarily mean the one physically above where "." points to. These days I
+think it's just handed off to the filesystem.)
+
+Anyway, path resolution starts with "." or "/" (although the "./" at the start
+of the path may be implicit), meaning it's relative to one of those two
+directories. Your current directory, and your current root directory. The
+chdir() syscall changes where "." points to, and the chroot() syscall changes
+where "/" points to. (Again, both are per-process which is why chroot only
+affects your current process and its child processes.)
+
+Note that chroot() does _not_ change where "." points to, and back before they
+put crazy security checks into the kernel your current directory could be
+somewhere you could no longer access after the chroot. (The command line
+chroot does a cd as well, the chroot _syscall_ is what I'm talking about.)
+
+The reason mounting something new over / has no obvious effect is the same
+reason mounting something over your current directory has no obvious effect:
+the . and / links aren't recalculated after a mount, so they still point to
+the same dentry they did before, even if that dentry is no longer accessible
+by other means. Note that "cd ." is a NOP, and "chroot /" is a nop; both look
+up the cached dentry and set it right back. They don't re-parse any paths,
+because they're what all paths your process uses would be relative to.
+
+That's why the careful sequencing above: we cd into the new mount point before
+we do the mount --move. Moving the mount point would otherwise make it
+totally inaccessible to is because cd-ing to the old path wouldn't give it to
+us anymore, and cd "/" just gives us the cached dentry from when the process
+was created (in this case the old initramfs one). But the "." symlink gives
+us the dentry of the filesystem we just moved, so we can then "chroot ." to
+copy that dentry to "/" and get the new filesystem. If we _didn't_ save that
+dentry in "." we couldn't get it back after the mount --move.
+
+(Yes, this is all screwy and I had to email questions to Linus Torvalds to get
+it straight myself. I keep meaning to write up a "how mount actually works"
+document someday...)
+*/
diff --git a/ap/app/busybox/src/util-linux/umount.c b/ap/app/busybox/src/util-linux/umount.c
new file mode 100644
index 0000000..4c2e882
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/umount.c
@@ -0,0 +1,206 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini umount implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2005 by Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//usage:#define umount_trivial_usage
+//usage: "[OPTIONS] FILESYSTEM|DIRECTORY"
+//usage:#define umount_full_usage "\n\n"
+//usage: "Unmount file systems\n"
+//usage: IF_FEATURE_UMOUNT_ALL(
+//usage: "\n -a Unmount all file systems" IF_FEATURE_MTAB_SUPPORT(" in /etc/mtab")
+//usage: )
+//usage: IF_FEATURE_MTAB_SUPPORT(
+//usage: "\n -n Don't erase /etc/mtab entries"
+//usage: )
+//usage: "\n -r Try to remount devices as read-only if mount is busy"
+//usage: "\n -l Lazy umount (detach filesystem)"
+//usage: "\n -f Force umount (i.e., unreachable NFS server)"
+//usage: IF_FEATURE_MOUNT_LOOP(
+//usage: "\n -D Don't free loop device even if it has been used"
+//usage: )
+//usage:
+//usage:#define umount_example_usage
+//usage: "$ umount /dev/hdc1\n"
+
+#include <mntent.h>
+#include <sys/mount.h>
+#include "libbb.h"
+
+#if defined(__dietlibc__)
+// TODO: This does not belong here.
+/* 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
+
+/* Ignored: -v -t -i
+ * bbox always acts as if -d is present.
+ * -D can be used to suppress it (bbox extension).
+ * Rationale:
+ * (1) util-linux's umount does it if "loop=..." is seen in /etc/mtab:
+ * thus, on many systems, bare umount _does_ drop loop devices.
+ * (2) many users request this feature.
+ */
+#define OPTION_STRING "fldDnra" "vt:i"
+#define OPT_FORCE (1 << 0) // Same as MNT_FORCE
+#define OPT_LAZY (1 << 1) // Same as MNT_DETACH
+//#define OPT_FREE_LOOP (1 << 2) // -d is assumed always present
+#define OPT_DONT_FREE_LOOP (1 << 3)
+#define OPT_NO_MTAB (1 << 4)
+#define OPT_REMOUNT (1 << 5)
+#define OPT_ALL (ENABLE_FEATURE_UMOUNT_ALL ? (1 << 6) : 0)
+
+int umount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int umount_main(int argc UNUSED_PARAM, char **argv)
+{
+ int doForce;
+ 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;
+
+ // MNT_FORCE and MNT_DETACH (from linux/fs.h) must match
+ // OPT_FORCE and OPT_LAZY, otherwise this trick won't work:
+ 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, bb_common_bufsiz1, sizeof(bb_common_bufsiz1))) {
+ /* 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;
+ }
+ endmntent(fp);
+ }
+
+ // 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;
+ }
+
+ // Loop through everything we're supposed to umount, and do so.
+ for (;;) {
+ int curstat;
+ char *zapit = *argv;
+ char *path;
+
+ // Do we already know what to umount this time through the loop?
+ if (m)
+ path = xstrdup(m->dir);
+ // 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++;
+ path = xmalloc_realpath(zapit);
+ if (path) {
+ for (m = mtl; m; m = m->next)
+ if (strcmp(path, m->dir) == 0 || strcmp(path, m->device) == 0)
+ break;
+ }
+ }
+ // If we couldn't find this sucker in /etc/mtab, punt by passing our
+ // command line argument straight to the umount syscall. Otherwise,
+ // umount the directory even if we were given the block device.
+ if (m) zapit = m->dir;
+
+ // Let's ask the thing nicely to unmount.
+ curstat = umount(zapit);
+
+ // Force the unmount, if necessary.
+ if (curstat && doForce)
+ curstat = umount2(zapit, doForce);
+
+ // If 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_DONT_FREE_LOOP) && m)
+ del_loop(m->device);
+ if (ENABLE_FEATURE_MTAB_SUPPORT && !(opt & OPT_NO_MTAB) && m)
+ erase_mtab(m->dir);
+ }
+
+ // Find next matching mtab entry for -a or umount /dev
+ // Note this means that "umount /dev/blah" will unmount all instances
+ // of /dev/blah, not just the most recent.
+ if (m) {
+ while ((m = m->next) != NULL)
+ // NB: if m is non-NULL, path is non-NULL as well
+ if ((opt & OPT_ALL) || strcmp(path, m->device) == 0)
+ break;
+ }
+ free(path);
+ }
+
+ // Free mtab list if necessary
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ while (mtl) {
+ m = mtl->next;
+ free(mtl->device);
+ free(mtl->dir);
+ free(mtl);
+ mtl = m;
+ }
+ }
+
+ return status;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/Kbuild.src b/ap/app/busybox/src/util-linux/volume_id/Kbuild.src
new file mode 100644
index 0000000..759fdaa
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/Kbuild.src
@@ -0,0 +1,47 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under GPLv2, see file LICENSE in this source tree.
+
+lib-y:=
+
+INSERT
+
+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_BTRFS) += btrfs.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_NILFS) += nilfs.o
+lib-$(CONFIG_FEATURE_VOLUMEID_NTFS) += ntfs.o
+lib-$(CONFIG_FEATURE_VOLUMEID_EXFAT) += exfat.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/ap/app/busybox/src/util-linux/volume_id/btrfs.c b/ap/app/busybox/src/util-linux/volume_id/btrfs.c
new file mode 100644
index 0000000..ee71d2e
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/btrfs.c
@@ -0,0 +1,108 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2009 Vladimir Dronnikov <dronnikov@gmail.com>
+ *
+ * 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 BTRFS_UUID_SIZE 16
+#define BTRFS_LABEL_SIZE 256
+#define BTRFS_CSUM_SIZE 32
+#define BTRFS_FSID_SIZE 16
+
+#define BTRFS_MAGIC "_BHRfS_M"
+
+struct btrfs_dev_item {
+ uint64_t devid;
+ uint64_t total_bytes;
+ uint64_t bytes_used;
+ uint32_t io_align;
+ uint32_t io_width;
+ uint32_t sector_size;
+ uint64_t type;
+ uint64_t generation;
+ uint64_t start_offset;
+ uint32_t dev_group;
+ uint8_t seek_speed;
+ uint8_t bandwidth;
+ uint8_t uuid[BTRFS_UUID_SIZE];
+ uint8_t fsid[BTRFS_UUID_SIZE];
+} PACKED;
+
+struct btrfs_super_block {
+ uint8_t csum[BTRFS_CSUM_SIZE];
+ uint8_t fsid[BTRFS_FSID_SIZE]; // UUID
+ uint64_t bytenr;
+ uint64_t flags;
+ uint8_t magic[8];
+ uint64_t generation;
+ uint64_t root;
+ uint64_t chunk_root;
+ uint64_t log_root;
+ uint64_t log_root_transid;
+ uint64_t total_bytes;
+ uint64_t bytes_used;
+ uint64_t root_dir_objectid;
+ uint64_t num_devices;
+ uint32_t sectorsize;
+ uint32_t nodesize;
+ uint32_t leafsize;
+ uint32_t stripesize;
+ uint32_t sys_chunk_array_size;
+ uint64_t chunk_root_generation;
+ uint64_t compat_flags;
+ uint64_t compat_ro_flags;
+ uint64_t incompat_flags;
+ uint16_t csum_type;
+ uint8_t root_level;
+ uint8_t chunk_root_level;
+ uint8_t log_root_level;
+ struct btrfs_dev_item dev_item;
+ uint8_t label[BTRFS_LABEL_SIZE]; // LABEL
+ // ...
+} PACKED;
+
+int FAST_FUNC volume_id_probe_btrfs(struct volume_id *id /*,uint64_t off*/)
+{
+ // btrfs has superblocks at 64K, 64M and 256G
+ // minimum btrfs size is 256M
+ // so we never step out the device if we analyze
+ // the first and the second superblocks
+ struct btrfs_super_block *sb;
+ unsigned off = 64;
+
+ while (off < 64*1024*1024) {
+ off *= 1024;
+ dbg("btrfs: probing at offset 0x%x", off);
+
+ sb = volume_id_get_buffer(id, off, sizeof(*sb));
+ if (sb == NULL)
+ return -1;
+
+ if (memcmp(sb->magic, BTRFS_MAGIC, 8) != 0)
+ return -1;
+ }
+
+ // N.B.: btrfs natively supports 256 (>VOLUME_ID_LABEL_SIZE) size labels
+ volume_id_set_label_string(id, sb->label, VOLUME_ID_LABEL_SIZE);
+ volume_id_set_uuid(id, sb->fsid, UUID_DCE);
+ IF_FEATURE_BLKID_TYPE(id->type = "btrfs";)
+
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/cramfs.c b/ap/app/busybox/src/util-linux/volume_id/cramfs.c
new file mode 100644
index 0000000..28e9970
--- /dev/null
+++ b/ap/app/busybox/src/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;
+ } PACKED info;
+ uint8_t name[16];
+} PACKED;
+
+int FAST_FUNC 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);
+ IF_FEATURE_BLKID_TYPE(id->type = "cramfs";)
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/exfat.c b/ap/app/busybox/src/util-linux/volume_id/exfat.c
new file mode 100644
index 0000000..a38a891
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/exfat.c
@@ -0,0 +1,130 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2012 S-G Bergh <sgb@systemasis.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 EXFAT_SB_OFFSET 0
+#define EXFAT_DIR_ENTRY_SZ 32
+#define EXFAT_MAX_DIR_ENTRIES 100
+
+struct exfat_super_block {
+/* 0x00 */ uint8_t boot_jump[3];
+/* 0x03 */ uint8_t fs_name[8];
+/* 0x0B */ uint8_t must_be_zero[53];
+/* 0x40 */ uint64_t partition_offset;
+/* 0x48 */ uint64_t volume_length;
+/* 0x50 */ uint32_t fat_offset; // Sector address of 1st FAT
+/* 0x54 */ uint32_t fat_size; // In sectors
+/* 0x58 */ uint32_t cluster_heap_offset; // Sector address of Data Region
+/* 0x5C */ uint32_t cluster_count;
+/* 0x60 */ uint32_t root_dir; // Cluster address of Root Directory
+/* 0x64 */ uint8_t vol_serial_nr[4]; // Volume ID
+/* 0x68 */ uint16_t fs_revision; // VV.MM
+/* 0x6A */ uint16_t vol_flags;
+/* 0x6C */ uint8_t bytes_per_sector; // Power of 2: 9 => 512, 12 => 4096
+/* 0x6D */ uint8_t sectors_per_cluster; // Power of 2
+/* 0x6E */ uint8_t nr_of_fats; // 2 for TexFAT
+/* 0x6F */ // ...
+} PACKED;
+
+struct exfat_dir_entry {
+/* 0x00 */ uint8_t entry_type;
+ union {
+ struct volume_label {
+/* 0x01 */ uint8_t char_count; // Length of label
+/* 0x02 */ uint16_t vol_label[11]; // UTF16 string without null termination
+/* 0x18 */ uint8_t reserved[8];
+/* 0x20 */ } PACKED label;
+ struct volume_guid {
+/* 0x01 */ uint8_t sec_count;
+/* 0x02 */ uint16_t set_checksum;
+/* 0x04 */ uint16_t flags;
+/* 0x06 */ uint8_t vol_guid[16];
+/* 0x16 */ uint8_t reserved[10];
+/* 0x20 */ } PACKED guid;
+ } PACKED type;
+} PACKED;
+
+int FAST_FUNC volume_id_probe_exfat(struct volume_id *id /*,uint64_t off*/)
+{
+ struct exfat_super_block *sb;
+ struct exfat_dir_entry *de;
+ unsigned sector_sz;
+ unsigned cluster_sz;
+ uint64_t root_dir_off;
+ unsigned count;
+ unsigned need_lbl_guid;
+
+ // Primary super block
+ dbg("exFAT: probing at offset 0x%x", EXFAT_SB_OFFSET);
+ sb = volume_id_get_buffer(id, EXFAT_SB_OFFSET, sizeof(*sb));
+
+ if (!sb)
+ return -1;
+
+ if (memcmp(sb->fs_name, "EXFAT ", 8) != 0)
+ return -1;
+
+ sector_sz = 1 << sb->bytes_per_sector;
+ cluster_sz = sector_sz << sb->sectors_per_cluster;
+ // There are no clusters 0 and 1, so the first cluster is 2.
+ root_dir_off = (uint64_t)EXFAT_SB_OFFSET +
+ // Hmm... should we cast sector_sz/cluster_sz to uint64_t?
+ (le32_to_cpu(sb->cluster_heap_offset)) * sector_sz +
+ (le32_to_cpu(sb->root_dir) - 2) * cluster_sz;
+ dbg("exFAT: sector size 0x%x bytes", sector_sz);
+ dbg("exFAT: cluster size 0x%x bytes", cluster_sz);
+ dbg("exFAT: root dir is at 0x%llx", (long long)root_dir_off);
+
+ // Use DOS uuid as fallback, if no GUID set
+ volume_id_set_uuid(id, sb->vol_serial_nr, UUID_DOS);
+
+ // EXFAT_MAX_DIR_ENTRIES is used as a safety belt.
+ // The Root Directory may hold an unlimited number of entries,
+ // so we do not want to check all. Usually label and GUID
+ // are in the beginning, but there are no guarantees.
+ need_lbl_guid = (1 << 0) | (1 << 1);
+ for (count = 0; count < EXFAT_MAX_DIR_ENTRIES; count++) {
+ de = volume_id_get_buffer(id, root_dir_off + (count * EXFAT_DIR_ENTRY_SZ), EXFAT_DIR_ENTRY_SZ);
+ if (de == NULL)
+ break;
+ if (de->entry_type == 0x00) {
+ // End of Directory Marker
+ dbg("exFAT: End of root directory reached after %u entries", count);
+ break;
+ }
+ if (de->entry_type == 0x83) {
+ // Volume Label Directory Entry
+ volume_id_set_label_unicode16(id, (uint8_t *)de->type.label.vol_label,
+ LE, 2 * de->type.label.char_count);
+ need_lbl_guid &= ~(1 << 0);
+ }
+ if (de->entry_type == 0xA0) {
+ // Volume GUID Directory Entry
+ volume_id_set_uuid(id, de->type.guid.vol_guid, UUID_DCE);
+ need_lbl_guid &= ~(1 << 1);
+ }
+ if (!need_lbl_guid)
+ break;
+ }
+
+ IF_FEATURE_BLKID_TYPE(id->type = "exfat";)
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/ext.c b/ap/app/busybox/src/util-linux/volume_id/ext.c
new file mode 100644
index 0000000..9745106
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/ext.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"
+#include "bb_e2fs_defs.h"
+
+#define EXT_SUPERBLOCK_OFFSET 0x400
+
+int FAST_FUNC 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->s_magic != cpu_to_le16(EXT2_SUPER_MAGIC)) {
+ 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, (void*)es->s_volume_name, 16);
+ volume_id_set_uuid(id, es->s_uuid, UUID_DCE);
+ dbg("ext: label '%s' uuid '%s'", id->label, id->uuid);
+
+#if ENABLE_FEATURE_BLKID_TYPE
+ if ((es->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_HUGE_FILE | EXT4_FEATURE_RO_COMPAT_DIR_NLINK))
+ || (es->s_feature_incompat & cpu_to_le32(EXT4_FEATURE_INCOMPAT_EXTENTS | EXT4_FEATURE_INCOMPAT_64BIT))
+ ) {
+ id->type = "ext4";
+ }
+ else if (es->s_feature_compat & cpu_to_le32(EXT3_FEATURE_COMPAT_HAS_JOURNAL))
+ id->type = "ext3";
+ else
+ id->type = "ext2";
+#endif
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/fat.c b/ap/app/busybox/src/util-linux/volume_id/fat.c
new file mode 100644
index 0000000..904fbb2
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/fat.c
@@ -0,0 +1,338 @@
+/*
+ * 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];
+ } 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];
+ } PACKED fat32;
+ } PACKED type;
+} 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;
+} 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 FAST_FUNC 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);
+ IF_FEATURE_BLKID_TYPE(id->type = "vfat";)
+
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/get_devname.c b/ap/app/busybox/src/util-linux/volume_id/get_devname.c
new file mode 100644
index 0000000..665cb9b
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/get_devname.c
@@ -0,0 +1,311 @@
+/* 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 source tree.
+ */
+#include <sys/mount.h> /* BLKGETSIZE64 */
+#if !defined(BLKGETSIZE64)
+# define BLKGETSIZE64 _IOR(0x12,114,size_t)
+#endif
+#include "volume_id_internal.h"
+
+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 */
+ IF_FEATURE_BLKID_TYPE(const char *type;)
+} *uuidCache;
+
+#if !ENABLE_FEATURE_BLKID_TYPE
+#define get_label_uuid(fd, label, uuid, type) \
+ get_label_uuid(fd, label, uuid)
+#define uuidcache_addentry(device, label, uuid, type) \
+ uuidcache_addentry(device, label, uuid)
+#endif
+
+/* 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, const char **type)
+{
+ 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'
+#if ENABLE_FEATURE_BLKID_TYPE
+ || vid->type != NULL
+#endif
+ ) {
+ *label = xstrndup(vid->label, sizeof(vid->label));
+ *uuid = xstrndup(vid->uuid, sizeof(vid->uuid));
+#if ENABLE_FEATURE_BLKID_TYPE
+ *type = vid->type;
+ dbg("found label '%s', uuid '%s', type '%s'", *label, *uuid, *type);
+#else
+ dbg("found label '%s', uuid '%s'", *label, *uuid);
+#endif
+ 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, const char *type)
+{
+ 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_FEATURE_BLKID_TYPE(last->type = type;)
+}
+
+/* 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)
+{
+ /* note: this check rejects links to devices, among other nodes */
+ if (!S_ISBLK(statbuf->st_mode))
+ return TRUE;
+
+ /* Users report that mucking with floppies (especially non-present
+ * ones) is significant PITA. This is a horribly dirty hack,
+ * but it is very useful in real world.
+ * If this will ever need to be enabled, consider using O_NONBLOCK.
+ */
+ if (major(statbuf->st_rdev) == 2)
+ return TRUE;
+
+ add_to_uuid_cache(device);
+
+ return TRUE;
+}
+
+static struct uuidCache_s*
+uuidcache_init(int scan_devices)
+{
+ dbg("DBG: uuidCache=%x, uuidCache");
+ if (uuidCache)
+ return uuidCache;
+
+ /* 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?) */
+ if (scan_devices)
+ recursive_action("/dev", ACTION_RECURSE,
+ uuidcache_check_device, /* file_action */
+ NULL, /* dir_action */
+ NULL, /* userData */
+ 0 /* depth */);
+
+ return uuidCache;
+}
+
+#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;
+
+ uc = uuidcache_init(/*scan_devices:*/ 1);
+ 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(int scan_devices)
+{
+ struct uuidCache_s *uc;
+
+ uc = uuidcache_init(scan_devices);
+ while (uc) {
+ printf("%s:", uc->device);
+ if (uc->label[0])
+ printf(" LABEL=\"%s\"", uc->label);
+ if (uc->uc_uuid[0])
+ printf(" UUID=\"%s\"", uc->uc_uuid);
+#if ENABLE_FEATURE_BLKID_TYPE
+ if (uc->type)
+ printf(" TYPE=\"%s\"", uc->type);
+#endif
+ bb_putchar('\n');
+ uc = uc->next;
+ }
+}
+
+int add_to_uuid_cache(const char *device)
+{
+ char *uuid = uuid; /* for compiler */
+ char *label = label;
+#if ENABLE_FEATURE_BLKID_TYPE
+ const char *type = type;
+#endif
+ int fd;
+
+ fd = open(device, O_RDONLY);
+ if (fd < 0)
+ return 0;
+
+ /* get_label_uuid() closes fd in all cases (success & failure) */
+ if (get_label_uuid(fd, &label, &uuid, &type) == 0) {
+ /* uuidcache_addentry() takes ownership of all four params */
+ uuidcache_addentry(xstrdup(device), /*ma, mi,*/ label, uuid, type);
+ return 1;
+ }
+ return 0;
+}
+
+
+/* Used by mount and findfs */
+
+char *get_devname_from_label(const char *spec)
+{
+ struct uuidCache_s *uc;
+
+ uc = uuidcache_init(/*scan_devices:*/ 1);
+ 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;
+
+ uc = uuidcache_init(/*scan_devices:*/ 1);
+ 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;
+}
+
+int resolve_mount_spec(char **fsname)
+{
+ char *tmp = *fsname;
+
+ if (strncmp(*fsname, "UUID=", 5) == 0)
+ tmp = get_devname_from_uuid(*fsname + 5);
+ else if (strncmp(*fsname, "LABEL=", 6) == 0)
+ tmp = get_devname_from_label(*fsname + 6);
+
+ if (tmp == *fsname)
+ return 0; /* no UUID= or LABEL= prefix found */
+
+ if (tmp)
+ *fsname = tmp;
+ return 1;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/hfs.c b/ap/app/busybox/src/util-linux/volume_id/hfs.c
new file mode 100644
index 0000000..3d9704d
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/hfs.c
@@ -0,0 +1,313 @@
+/*
+ * 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];
+} 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;
+} PACKED;
+
+struct hfsplus_bnode_descriptor {
+ uint32_t next;
+ uint32_t prev;
+ uint8_t type;
+ uint8_t height;
+ uint16_t num_recs;
+ uint16_t reserved;
+} 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;
+} PACKED;
+
+struct hfsplus_catalog_key {
+ uint16_t key_len;
+ uint32_t parent_id;
+ uint16_t unicode_len;
+ uint8_t unicode[255 * 2];
+} PACKED;
+
+struct hfsplus_extent {
+ uint32_t start_block;
+ uint32_t block_count;
+} 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];
+} 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;
+} PACKED;
+
+#define HFS_SUPERBLOCK_OFFSET 0x400
+#define HFS_NODE_LEAF 0xff
+#define HFSPLUS_POR_CNID 1
+
+static void FAST_FUNC hfs_set_uuid(struct volume_id *id, const uint8_t *hfs_id)
+{
+#define hfs_id_len 8
+ md5_ctx_t md5c;
+ uint8_t uuid[16];
+ unsigned i;
+
+ for (i = 0; i < hfs_id_len; i++)
+ if (hfs_id[i] != 0)
+ goto do_md5;
+ return;
+ do_md5:
+ md5_begin(&md5c);
+ md5_hash(&md5c, "\263\342\17\71\362\222\21\326\227\244\0\60\145\103\354\254", 16);
+ md5_hash(&md5c, hfs_id, hfs_id_len);
+ md5_end(&md5c, uuid);
+ uuid[6] = 0x30 | (uuid[6] & 0x0f);
+ uuid[8] = 0x80 | (uuid[8] & 0x3f);
+ volume_id_set_uuid(id, uuid, UUID_DCE);
+}
+
+int FAST_FUNC 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) ;
+ }
+
+ hfs_set_uuid(id, hfs->finder_info.id);
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ IF_FEATURE_BLKID_TYPE(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:
+ hfs_set_uuid(id, hfsplus->finder_info.id);
+
+ 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);
+ IF_FEATURE_BLKID_TYPE(id->type = "hfsplus";)
+
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/iso9660.c b/ap/app/busybox/src/util-linux/volume_id/iso9660.c
new file mode 100644
index 0000000..1d7693a
--- /dev/null
+++ b/ap/app/busybox/src/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];
+} PACKED;
+
+struct high_sierra_volume_descriptor {
+ uint8_t foo[8];
+ uint8_t type;
+ uint8_t id[4];
+ uint8_t version;
+} PACKED;
+
+int FAST_FUNC 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);
+ IF_FEATURE_BLKID_TYPE(id->type = "iso9660";)
+
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/jfs.c b/ap/app/busybox/src/util-linux/volume_id/jfs.c
new file mode 100644
index 0000000..5333af2
--- /dev/null
+++ b/ap/app/busybox/src/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];
+} PACKED;
+
+#define JFS_SUPERBLOCK_OFFSET 0x8000
+
+int FAST_FUNC 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);
+ IF_FEATURE_BLKID_TYPE(id->type = "jfs";)
+
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/linux_raid.c b/ap/app/busybox/src/util-linux/volume_id/linux_raid.c
new file mode 100644
index 0000000..209eaab
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/linux_raid.c
@@ -0,0 +1,81 @@
+/*
+ * 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;
+} PACKED;
+
+#define MD_RESERVED_BYTES 0x10000
+#define MD_MAGIC 0xa92b4efc
+
+int FAST_FUNC volume_id_probe_linux_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size)
+{
+ typedef uint32_t aliased_uint32_t FIX_ALIASING;
+#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;
+
+ *(aliased_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);
+ IF_FEATURE_BLKID_TYPE(id->type = "linux_raid_member";)
+
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/linux_swap.c b/ap/app/busybox/src/util-linux/volume_id/linux_swap.c
new file mode 100644
index 0000000..1ee534a
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/linux_swap.c
@@ -0,0 +1,78 @@
+/*
+ * 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];
+} PACKED;
+
+#define LARGEST_PAGESIZE 0x4000
+
+int FAST_FUNC 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
+ || memcmp(buf, "S1SUSPEND", 9) == 0
+ || memcmp(buf, "S2SUSPEND", 9) == 0
+ || memcmp(buf, "ULSUSPEND", 9) == 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);
+ IF_FEATURE_BLKID_TYPE(id->type = "swap";)
+
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/luks.c b/ap/app/busybox/src/util-linux/volume_id/luks.c
new file mode 100644
index 0000000..f9b3766
--- /dev/null
+++ b/ap/app/busybox/src/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 FAST_FUNC 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);
+ IF_FEATURE_BLKID_TYPE(id->type = "crypto_LUKS";)
+
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/nilfs.c b/ap/app/busybox/src/util-linux/volume_id/nilfs.c
new file mode 100644
index 0000000..b88a9e4
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/nilfs.c
@@ -0,0 +1,96 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2012 S-G Bergh <sgb@systemasis.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 NILFS_UUID_SIZE 16
+#define NILFS_LABEL_SIZE 80
+#define NILFS_SB1_OFFSET 0x400
+#define NILFS_SB2_OFFSET 0x1000
+#define NILFS_MAGIC 0x3434
+
+struct nilfs2_super_block {
+/* 0x00 */ uint32_t s_rev_level; // Major revision level.
+/* 0x04 */ uint16_t s_minor_rev_level; // Minor revision level.
+/* 0x06 */ uint16_t s_magic; // Magic signature.
+/* 0x08 */ uint16_t s_bytes;
+/* 0x0A */ uint16_t s_flags;
+/* 0x0C */ uint32_t s_crc_seed;
+/* 0x10 */ uint32_t s_sum;
+/* 0x14 */ uint32_t s_log_block_size;
+/* 0x18 */ uint64_t s_nsegments;
+/* 0x20 */ uint64_t s_dev_size; // Block device size in bytes.
+/* 0x28 */ uint64_t s_first_data_block;
+/* 0x30 */ uint32_t s_blocks_per_segment;
+/* 0x34 */ uint32_t s_r_segments_percentage;
+/* 0x38 */ uint64_t s_last_cno;
+/* 0x40 */ uint64_t s_last_pseg;
+/* 0x48 */ uint64_t s_last_seq;
+/* 0x50 */ uint64_t s_free_blocks_count;
+/* 0x58 */ uint64_t s_ctime;
+/* 0x60 */ uint64_t s_mtime;
+/* 0x68 */ uint64_t s_wtime;
+/* 0x70 */ uint16_t s_mnt_count;
+/* 0x72 */ uint16_t s_max_mnt_count;
+/* 0x74 */ uint16_t s_state;
+/* 0x76 */ uint16_t s_errors;
+/* 0x78 */ uint64_t s_lastcheck;
+/* 0x80 */ uint32_t s_checkinterval;
+/* 0x84 */ uint32_t s_creator_os;
+/* 0x88 */ uint16_t s_def_resuid;
+/* 0x8A */ uint16_t s_def_resgid;
+/* 0x8C */ uint32_t s_first_ino;
+/* 0x90 */ uint16_t s_inode_size;
+/* 0x92 */ uint16_t s_dat_entry_size;
+/* 0x94 */ uint16_t s_checkpoint_size;
+/* 0x96 */ uint16_t s_segment_usage_size;
+/* 0x98 */ uint8_t s_uuid[NILFS_UUID_SIZE]; // 128-bit UUID for volume.
+/* 0xA8 */ uint8_t s_volume_name[NILFS_LABEL_SIZE]; // Volume label.
+/* 0xF8 */ // ...
+} PACKED;
+
+int FAST_FUNC volume_id_probe_nilfs(struct volume_id *id /*,uint64_t off*/)
+{
+ struct nilfs2_super_block *sb;
+
+ // Primary super block
+ dbg("nilfs: probing at offset 0x%x", NILFS_SB1_OFFSET);
+
+ sb = volume_id_get_buffer(id, NILFS_SB1_OFFSET, sizeof(*sb));
+
+ if (sb == NULL)
+ return -1;
+
+ if (sb->s_magic != NILFS_MAGIC)
+ return -1;
+
+ // The secondary superblock is not always used, so ignore it for now.
+ // When used it is at 4K from the end of the partition (sb->s_dev_size - NILFS_SB2_OFFSET).
+
+ volume_id_set_label_string(id, sb->s_volume_name, NILFS_LABEL_SIZE < VOLUME_ID_LABEL_SIZE ?
+ NILFS_LABEL_SIZE : VOLUME_ID_LABEL_SIZE);
+ volume_id_set_uuid(id, sb->s_uuid, UUID_DCE);
+
+ if (sb->s_rev_level == 2)
+ IF_FEATURE_BLKID_TYPE(id->type = "nilfs2");
+
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/ntfs.c b/ap/app/busybox/src/util-linux/volume_id/ntfs.c
new file mode 100644
index 0000000..7b2612f
--- /dev/null
+++ b/ap/app/busybox/src/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;
+} 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;
+} 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;
+} PACKED;
+
+struct volume_info {
+ uint64_t reserved;
+ uint8_t major_ver;
+ uint8_t minor_ver;
+} 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 FAST_FUNC 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);
+ IF_FEATURE_BLKID_TYPE(id->type = "ntfs";)
+
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/ocfs2.c b/ap/app/busybox/src/util-linux/volume_id/ocfs2.c
new file mode 100644
index 0000000..fcdb151
--- /dev/null
+++ b/ap/app/busybox/src/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 */
+} PACKED;
+
+int FAST_FUNC 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);
+ IF_FEATURE_BLKID_TYPE(id->type = "ocfs2";)
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/reiserfs.c b/ap/app/busybox/src/util-linux/volume_id/reiserfs.c
new file mode 100644
index 0000000..67b4a18
--- /dev/null
+++ b/ap/app/busybox/src/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];
+} PACKED;
+
+struct reiser4_super_block {
+ uint8_t magic[16];
+ uint16_t dummy[2];
+ uint8_t uuid[16];
+ uint8_t label[16];
+ uint64_t dummy2;
+} PACKED;
+
+#define REISERFS1_SUPERBLOCK_OFFSET 0x2000
+#define REISERFS_SUPERBLOCK_OFFSET 0x10000
+
+int FAST_FUNC 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);
+ IF_FEATURE_BLKID_TYPE(id->type = "reiserfs";)
+
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/romfs.c b/ap/app/busybox/src/util-linux/volume_id/romfs.c
new file mode 100644
index 0000000..15653be
--- /dev/null
+++ b/ap/app/busybox/src/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[];
+} PACKED;
+
+int FAST_FUNC 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);
+ IF_FEATURE_BLKID_TYPE(id->type = "romfs";)
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/squashfs.c b/ap/app/busybox/src/util-linux/volume_id/squashfs.c
new file mode 100644
index 0000000..c5b4f9c
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/squashfs.c
@@ -0,0 +1,49 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2012 S-G Bergh <sgb@systemasis.org>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_SQUASHFS) += squashfs.o
+
+#include "volume_id_internal.h"
+
+struct squashfs_superblock {
+ uint32_t magic;
+/*
+ uint32_t dummy[6];
+ uint16_t major;
+ uint16_t minor;
+*/
+} PACKED;
+
+int FAST_FUNC volume_id_probe_squashfs(struct volume_id *id /*,uint64_t off*/)
+{
+#define off ((uint64_t)0)
+ struct squashfs_superblock *sb;
+
+ dbg("SquashFS: probing at offset 0x%llx", (unsigned long long) off);
+ sb = volume_id_get_buffer(id, off, 0x200);
+ if (!sb)
+ return -1;
+
+ // Old SquashFS (pre 4.0) can be both big and little endian, so test for both.
+ // Likewise, it is commonly used in firwmare with some non-standard signatures.
+#define pack(a,b,c,d) ( (uint32_t)((a * 256 + b) * 256 + c) * 256 + d )
+#define SIG1 pack('s','q','s','h')
+#define SIG2 pack('h','s','q','s')
+#define SIG3 pack('s','h','s','q')
+#define SIG4 pack('q','s','h','s')
+ if (sb->magic == SIG1
+ || sb->magic == SIG2
+ || sb->magic == SIG3
+ || sb->magic == SIG4
+ ) {
+ IF_FEATURE_BLKID_TYPE(id->type = "squashfs";)
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/sysv.c b/ap/app/busybox/src/util-linux/volume_id/sysv.c
new file mode 100644
index 0000000..6eb9646
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/sysv.c
@@ -0,0 +1,125 @@
+/*
+ * 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;
+} 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;
+} 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 FAST_FUNC 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);
+ IF_FEATURE_BLKID_TYPE(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);
+ IF_FEATURE_BLKID_TYPE(id->type = "xenix";)
+ goto found;
+ }
+ }
+
+ return -1;
+
+ found:
+// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/udf.c b/ap/app/busybox/src/util-linux/volume_id/udf.c
new file mode 100644
index 0000000..d3747fb
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/udf.c
@@ -0,0 +1,172 @@
+/*
+ * 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;
+ } PACKED tag;
+ union {
+ struct anchor_descriptor {
+ uint32_t length;
+ uint32_t location;
+ } PACKED anchor;
+ struct primary_descriptor {
+ uint32_t seq_num;
+ uint32_t desc_num;
+ struct dstring {
+ uint8_t clen;
+ uint8_t c[31];
+ } PACKED ident;
+ } PACKED primary;
+ } PACKED type;
+} PACKED;
+
+struct volume_structure_descriptor {
+ uint8_t type;
+ uint8_t id[5];
+ uint8_t version;
+} PACKED;
+
+#define UDF_VSD_OFFSET 0x8000
+
+int FAST_FUNC 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);
+ IF_FEATURE_BLKID_TYPE(id->type = "udf";)
+ return 0;
+}
diff --git a/ap/app/busybox/src/util-linux/volume_id/unused_highpoint.c b/ap/app/busybox/src/util-linux/volume_id/unused_highpoint.c
new file mode 100644
index 0000000..17b7b32
--- /dev/null
+++ b/ap/app/busybox/src/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;
+} PACKED;
+
+struct hpt45x_meta {
+ uint32_t magic;
+} 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 FAST_FUNC 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 FAST_FUNC 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/ap/app/busybox/src/util-linux/volume_id/unused_hpfs.c b/ap/app/busybox/src/util-linux/volume_id/unused_hpfs.c
new file mode 100644
index 0000000..4429524
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/unused_hpfs.c
@@ -0,0 +1,48 @@
+/*
+ * 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;
+} PACKED;
+
+#define HPFS_SUPERBLOCK_OFFSET 0x2000
+
+int FAST_FUNC 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/ap/app/busybox/src/util-linux/volume_id/unused_isw_raid.c b/ap/app/busybox/src/util-linux/volume_id/unused_isw_raid.c
new file mode 100644
index 0000000..7ab47b3
--- /dev/null
+++ b/ap/app/busybox/src/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;
+} PACKED;
+
+#define ISW_SIGNATURE "Intel Raid ISM Cfg Sig. "
+
+
+int FAST_FUNC 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/ap/app/busybox/src/util-linux/volume_id/unused_lsi_raid.c b/ap/app/busybox/src/util-linux/volume_id/unused_lsi_raid.c
new file mode 100644
index 0000000..e6cc8ed
--- /dev/null
+++ b/ap/app/busybox/src/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];
+} PACKED;
+
+#define LSI_SIGNATURE "$XIDE$"
+
+int FAST_FUNC 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/ap/app/busybox/src/util-linux/volume_id/unused_lvm.c b/ap/app/busybox/src/util-linux/volume_id/unused_lvm.c
new file mode 100644
index 0000000..2206498
--- /dev/null
+++ b/ap/app/busybox/src/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];
+} 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];
+} PACKED;
+
+#define LVM1_SB_OFF 0x400
+
+int FAST_FUNC 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 FAST_FUNC 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/ap/app/busybox/src/util-linux/volume_id/unused_mac.c b/ap/app/busybox/src/util-linux/volume_id/unused_mac.c
new file mode 100644
index 0000000..e8deb97
--- /dev/null
+++ b/ap/app/busybox/src/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;
+} 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];
+} PACKED;
+
+int FAST_FUNC 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/ap/app/busybox/src/util-linux/volume_id/unused_minix.c b/ap/app/busybox/src/util-linux/volume_id/unused_minix.c
new file mode 100644
index 0000000..a3e1077
--- /dev/null
+++ b/ap/app/busybox/src/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;
+} PACKED;
+
+#define MINIX_SUPERBLOCK_OFFSET 0x400
+
+int FAST_FUNC 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/ap/app/busybox/src/util-linux/volume_id/unused_msdos.c b/ap/app/busybox/src/util-linux/volume_id/unused_msdos.c
new file mode 100644
index 0000000..2e8cb19
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/unused_msdos.c
@@ -0,0 +1,195 @@
+/*
+ * 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;
+} 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 FAST_FUNC 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/ap/app/busybox/src/util-linux/volume_id/unused_nvidia_raid.c b/ap/app/busybox/src/util-linux/volume_id/unused_nvidia_raid.c
new file mode 100644
index 0000000..9e84729
--- /dev/null
+++ b/ap/app/busybox/src/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;
+} PACKED;
+
+#define NVIDIA_SIGNATURE "NVIDIA"
+
+int FAST_FUNC 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/ap/app/busybox/src/util-linux/volume_id/unused_promise_raid.c b/ap/app/busybox/src/util-linux/volume_id/unused_promise_raid.c
new file mode 100644
index 0000000..0b0d006
--- /dev/null
+++ b/ap/app/busybox/src/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];
+} PACKED;
+
+#define PDC_CONFIG_OFF 0x1200
+#define PDC_SIGNATURE "Promise Technology, Inc."
+
+int FAST_FUNC 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/ap/app/busybox/src/util-linux/volume_id/unused_silicon_raid.c b/ap/app/busybox/src/util-linux/volume_id/unused_silicon_raid.c
new file mode 100644
index 0000000..878b881
--- /dev/null
+++ b/ap/app/busybox/src/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;
+} PACKED;
+
+#define SILICON_MAGIC 0x2F000000
+
+int FAST_FUNC 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/ap/app/busybox/src/util-linux/volume_id/unused_ufs.c b/ap/app/busybox/src/util-linux/volume_id/unused_ufs.c
new file mode 100644
index 0000000..9f925d9
--- /dev/null
+++ b/ap/app/busybox/src/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;
+ } 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];
+ } 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];
+ } PACKED fs_cstotal;
+ struct ufs_timeval {
+ int32_t tv_sec;
+ int32_t tv_usec;
+ } PACKED fs_time;
+ int64_t fs_size;
+ int64_t fs_dsize;
+ uint64_t fs_csaddr;
+ int64_t fs_pendingblocks;
+ int32_t fs_pendinginodes;
+ } 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];
+ } 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];
+ } 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;
+ } 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];
+} PACKED;
+
+#define UFS_MAGIC 0x00011954
+#define UFS2_MAGIC 0x19540119
+#define UFS_MAGIC_FEA 0x00195612
+#define UFS_MAGIC_LFN 0x00095014
+
+int FAST_FUNC 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/ap/app/busybox/src/util-linux/volume_id/unused_via_raid.c b/ap/app/busybox/src/util-linux/volume_id/unused_via_raid.c
new file mode 100644
index 0000000..a11eec1
--- /dev/null
+++ b/ap/app/busybox/src/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;
+ } PACKED array;
+ uint32_t serial_checksum[8];
+ uint8_t checksum;
+} PACKED;
+
+#define VIA_SIGNATURE 0xAA55
+
+int FAST_FUNC 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/ap/app/busybox/src/util-linux/volume_id/util.c b/ap/app/busybox/src/util-linux/volume_id/util.c
new file mode 100644
index 0000000..061545f
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/util.c
@@ -0,0 +1,265 @@
+/*
+ * 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)
+ break;
+ if (j+1 >= len)
+ break;
+ if (c < 0x80) {
+ /* 0xxxxxxx */
+ } else {
+ uint8_t topbits = 0xc0;
+ if (j+2 >= len)
+ break;
+ if (c < 0x800) {
+ /* 110yyyxx 10xxxxxx */
+ } else {
+ if (j+3 >= len)
+ break;
+ /* 1110yyyy 10yyyyxx 10xxxxxx */
+ str[j++] = (uint8_t) (0xe0 | (c >> 12));
+ topbits = 0x80;
+ }
+ str[j++] = (uint8_t) (topbits | ((c >> 6) & 0x3f));
+ c = 0x80 | (c & 0x3f);
+ }
+ str[j++] = (uint8_t) c;
+ }
+ 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 = (format == UUID_DCE_STRING ? VOLUME_ID_UUID_SIZE : 4 << format);
+
+// 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_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/ap/app/busybox/src/util-linux/volume_id/volume_id.c b/ap/app/busybox/src/util-linux/volume_id/volume_id.c
new file mode 100644
index 0000000..f0fc84c
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/volume_id.c
@@ -0,0 +1,255 @@
+/*
+ * 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 FAST_FUNC (*raid_probe_fptr)(struct volume_id *id, /*uint64_t off,*/ uint64_t size);
+typedef int FAST_FUNC (*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_EXFAT
+ volume_id_probe_exfat,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_MAC
+ volume_id_probe_mac_partition_map,
+#endif
+#if ENABLE_FEATURE_VOLUMEID_SQUASHFS
+ volume_id_probe_squashfs,
+#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_BTRFS
+ volume_id_probe_btrfs,
+#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_NILFS
+ volume_id_probe_nilfs,
+#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 FAST_FUNC 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* FAST_FUNC 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* FAST_FUNC 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("can't mknod(%s)", tmp_node);
+
+ id = volume_id_open_node(tmp_node);
+ unlink(tmp_node);
+ free(tmp_node);
+ return id;
+}
+#endif
+
+void FAST_FUNC 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/ap/app/busybox/src/util-linux/volume_id/volume_id_internal.h b/ap/app/busybox/src/util-linux/volume_id/volume_id_internal.h
new file mode 100644
index 0000000..3f02bd5
--- /dev/null
+++ b/ap/app/busybox/src/util-linux/volume_id/volume_id_internal.h
@@ -0,0 +1,240 @@
+/*
+ * 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;
+#if ENABLE_FEATURE_BLKID_TYPE
+ const char *type;
+#endif
+};
+
+struct volume_id* FAST_FUNC volume_id_open_node(int fd);
+int FAST_FUNC volume_id_probe_all(struct volume_id *id, /*uint64_t off,*/ uint64_t size);
+void FAST_FUNC 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
+
+/* volume_id_set_uuid(id,buf,fmt) assumes size of uuid buf
+ * by shifting: 4 << fmt, except for fmt == UUID_DCE_STRING.
+ * The constants below should match sizes.
+ */
+enum uuid_format {
+ UUID_DOS = 0, /* 4 bytes */
+ UUID_NTFS = 1, /* 8 bytes */
+ UUID_DCE = 2, /* 16 bytes */
+ UUID_DCE_STRING = 3, /* 36 bytes (VOLUME_ID_UUID_SIZE) */
+};
+
+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 FAST_FUNC volume_id_probe_highpoint_37x_raid(struct volume_id *id /*,uint64_t off*/);
+//int FAST_FUNC volume_id_probe_highpoint_45x_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size);
+
+//int FAST_FUNC volume_id_probe_intel_software_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size);
+
+int FAST_FUNC volume_id_probe_linux_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size);
+
+//int FAST_FUNC volume_id_probe_lsi_mega_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size);
+
+//int FAST_FUNC volume_id_probe_nvidia_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size);
+
+//int FAST_FUNC volume_id_probe_promise_fasttrack_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size);
+
+//int FAST_FUNC volume_id_probe_silicon_medley_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size);
+
+//int FAST_FUNC volume_id_probe_via_raid(struct volume_id *id /*,uint64_t off*/, uint64_t size);
+
+//int FAST_FUNC volume_id_probe_lvm1(struct volume_id *id /*,uint64_t off*/);
+//int FAST_FUNC volume_id_probe_lvm2(struct volume_id *id /*,uint64_t off*/);
+
+/* FS */
+
+int FAST_FUNC volume_id_probe_btrfs(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_cramfs(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_ext(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_vfat(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_hfs_hfsplus(struct volume_id *id /*,uint64_t off*/);
+
+//int FAST_FUNC volume_id_probe_hpfs(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_iso9660(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_jfs(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_linux_swap(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_luks(struct volume_id *id /*,uint64_t off*/);
+
+//int FAST_FUNC volume_id_probe_mac_partition_map(struct volume_id *id /*,uint64_t off*/);
+
+//int FAST_FUNC volume_id_probe_minix(struct volume_id *id /*,uint64_t off*/);
+
+//int FAST_FUNC volume_id_probe_msdos_part_table(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_nilfs(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_exfat(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_ocfs2(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_reiserfs(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_romfs(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_squashfs(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_sysv(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_udf(struct volume_id *id /*,uint64_t off*/);
+
+//int FAST_FUNC volume_id_probe_ufs(struct volume_id *id /*,uint64_t off*/);
+
+int FAST_FUNC volume_id_probe_xfs(struct volume_id *id /*,uint64_t off*/);
+
+POP_SAVED_FUNCTION_VISIBILITY
diff --git a/ap/app/busybox/src/util-linux/volume_id/xfs.c b/ap/app/busybox/src/util-linux/volume_id/xfs.c
new file mode 100644
index 0000000..8474602
--- /dev/null
+++ b/ap/app/busybox/src/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;
+} PACKED;
+
+int FAST_FUNC 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);
+ IF_FEATURE_BLKID_TYPE(id->type = "xfs";)
+
+ return 0;
+}